aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaxence Lange <maxence@artificial-owl.com>2024-11-28 14:21:34 -0100
committerMaxence Lange <maxence@artificial-owl.com>2024-12-04 09:30:55 -0100
commit4b0662005582e7a502b0de8e5e7e52f1675f3809 (patch)
treeb58732f585e5c33384f487e8067f59862771f198
parent862a41111855314a9bf0d186ed02688386b70d73 (diff)
downloadnextcloud-server-4b0662005582e7a502b0de8e5e7e52f1675f3809.tar.gz
nextcloud-server-4b0662005582e7a502b0de8e5e7e52f1675f3809.zip
feat(signatory): switch to qbmapper
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
-rw-r--r--apps/cloud_federation_api/lib/Controller/RequestHandlerController.php6
-rw-r--r--lib/composer/composer/autoload_classmap.php16
-rw-r--r--lib/composer/composer/autoload_static.php16
-rw-r--r--lib/private/OCM/Model/OCMProvider.php11
-rw-r--r--lib/private/OCM/OCMSignatoryManager.php21
-rw-r--r--lib/private/Security/IdentityProof/Manager.php8
-rw-r--r--lib/private/Security/Signature/Db/SignatoryMapper.php114
-rw-r--r--lib/private/Security/Signature/Model/IncomingSignedRequest.php52
-rw-r--r--lib/private/Security/Signature/Model/OutgoingSignedRequest.php78
-rw-r--r--lib/private/Security/Signature/Model/Signatory.php147
-rw-r--r--lib/private/Security/Signature/Model/SignedRequest.php73
-rw-r--r--lib/private/Security/Signature/SignatureManager.php245
-rw-r--r--lib/public/OCM/IOCMProvider.php13
-rw-r--r--lib/unstable/Security/Signature/Enum/SignatoryStatus.php (renamed from lib/unstable/Security/Signature/Model/SignatoryStatus.php)2
-rw-r--r--lib/unstable/Security/Signature/Enum/SignatoryType.php (renamed from lib/unstable/Security/Signature/Model/SignatoryType.php)6
-rw-r--r--lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php (renamed from lib/unstable/Security/Signature/SignatureAlgorithm.php)2
-rw-r--r--lib/unstable/Security/Signature/IIncomingSignedRequest.php (renamed from lib/unstable/Security/Signature/Model/IIncomingSignedRequest.php)14
-rw-r--r--lib/unstable/Security/Signature/IOutgoingSignedRequest.php (renamed from lib/unstable/Security/Signature/Model/IOutgoingSignedRequest.php)33
-rw-r--r--lib/unstable/Security/Signature/ISignatoryManager.php10
-rw-r--r--lib/unstable/Security/Signature/ISignatureManager.php8
-rw-r--r--lib/unstable/Security/Signature/ISignedRequest.php (renamed from lib/unstable/Security/Signature/Model/ISignedRequest.php)44
-rw-r--r--lib/unstable/Security/Signature/Model/ISignatory.php160
-rw-r--r--lib/unstable/Security/Signature/Model/Signatory.php165
23 files changed, 579 insertions, 665 deletions
diff --git a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php
index e277b9b6389..a243d286c71 100644
--- a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php
+++ b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php
@@ -10,8 +10,8 @@ use NCU\Security\Signature\Exceptions\IncomingRequestException;
use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
use NCU\Security\Signature\Exceptions\SignatureException;
use NCU\Security\Signature\Exceptions\SignatureNotFoundException;
+use NCU\Security\Signature\IIncomingSignedRequest;
use NCU\Security\Signature\ISignatureManager;
-use NCU\Security\Signature\Model\IIncomingSignedRequest;
use OC\OCM\OCMSignatoryManager;
use OCA\CloudFederationAPI\Config;
use OCA\CloudFederationAPI\ResponseDefinitions;
@@ -373,7 +373,7 @@ class RequestHandlerController extends Controller {
if ($signedRequest === null) {
$instance = $this->getHostFromFederationId($value);
try {
- $this->signatureManager->searchSignatory($instance);
+ $this->signatureManager->getSignatory($instance);
throw new IncomingRequestException('instance is supposed to sign its request');
} catch (SignatoryNotFoundException) {
return;
@@ -434,7 +434,7 @@ class RequestHandlerController extends Controller {
$instance = $this->getHostFromFederationId($entry);
if ($signedRequest === null) {
try {
- $this->signatureManager->searchSignatory($instance);
+ $this->signatureManager->getSignatory($instance);
throw new IncomingRequestException('instance is supposed to sign its request');
} catch (SignatoryNotFoundException) {
return;
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index bcffae9aff3..89e53c98602 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -12,6 +12,9 @@ return array(
'NCU\\Config\\Exceptions\\UnknownKeyException' => $baseDir . '/lib/unstable/Config/Exceptions/UnknownKeyException.php',
'NCU\\Config\\IUserConfig' => $baseDir . '/lib/unstable/Config/IUserConfig.php',
'NCU\\Config\\ValueType' => $baseDir . '/lib/unstable/Config/ValueType.php',
+ 'NCU\\Security\\Signature\\Enum\\SignatoryStatus' => $baseDir . '/lib/unstable/Security/Signature/Enum/SignatoryStatus.php',
+ 'NCU\\Security\\Signature\\Enum\\SignatoryType' => $baseDir . '/lib/unstable/Security/Signature/Enum/SignatoryType.php',
+ 'NCU\\Security\\Signature\\Enum\\SignatureAlgorithm' => $baseDir . '/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php',
'NCU\\Security\\Signature\\Exceptions\\IdentityNotFoundException' => $baseDir . '/lib/unstable/Security/Signature/Exceptions/IdentityNotFoundException.php',
'NCU\\Security\\Signature\\Exceptions\\IncomingRequestException' => $baseDir . '/lib/unstable/Security/Signature/Exceptions/IncomingRequestException.php',
'NCU\\Security\\Signature\\Exceptions\\InvalidKeyOriginException' => $baseDir . '/lib/unstable/Security/Signature/Exceptions/InvalidKeyOriginException.php',
@@ -22,15 +25,12 @@ return array(
'NCU\\Security\\Signature\\Exceptions\\SignatureElementNotFoundException' => $baseDir . '/lib/unstable/Security/Signature/Exceptions/SignatureElementNotFoundException.php',
'NCU\\Security\\Signature\\Exceptions\\SignatureException' => $baseDir . '/lib/unstable/Security/Signature/Exceptions/SignatureException.php',
'NCU\\Security\\Signature\\Exceptions\\SignatureNotFoundException' => $baseDir . '/lib/unstable/Security/Signature/Exceptions/SignatureNotFoundException.php',
+ 'NCU\\Security\\Signature\\IIncomingSignedRequest' => $baseDir . '/lib/unstable/Security/Signature/IIncomingSignedRequest.php',
+ 'NCU\\Security\\Signature\\IOutgoingSignedRequest' => $baseDir . '/lib/unstable/Security/Signature/IOutgoingSignedRequest.php',
'NCU\\Security\\Signature\\ISignatoryManager' => $baseDir . '/lib/unstable/Security/Signature/ISignatoryManager.php',
'NCU\\Security\\Signature\\ISignatureManager' => $baseDir . '/lib/unstable/Security/Signature/ISignatureManager.php',
- 'NCU\\Security\\Signature\\Model\\IIncomingSignedRequest' => $baseDir . '/lib/unstable/Security/Signature/Model/IIncomingSignedRequest.php',
- 'NCU\\Security\\Signature\\Model\\IOutgoingSignedRequest' => $baseDir . '/lib/unstable/Security/Signature/Model/IOutgoingSignedRequest.php',
- 'NCU\\Security\\Signature\\Model\\ISignatory' => $baseDir . '/lib/unstable/Security/Signature/Model/ISignatory.php',
- 'NCU\\Security\\Signature\\Model\\ISignedRequest' => $baseDir . '/lib/unstable/Security/Signature/Model/ISignedRequest.php',
- 'NCU\\Security\\Signature\\Model\\SignatoryStatus' => $baseDir . '/lib/unstable/Security/Signature/Model/SignatoryStatus.php',
- 'NCU\\Security\\Signature\\Model\\SignatoryType' => $baseDir . '/lib/unstable/Security/Signature/Model/SignatoryType.php',
- 'NCU\\Security\\Signature\\SignatureAlgorithm' => $baseDir . '/lib/unstable/Security/Signature/SignatureAlgorithm.php',
+ 'NCU\\Security\\Signature\\ISignedRequest' => $baseDir . '/lib/unstable/Security/Signature/ISignedRequest.php',
+ 'NCU\\Security\\Signature\\Model\\Signatory' => $baseDir . '/lib/unstable/Security/Signature/Model/Signatory.php',
'OCP\\Accounts\\IAccount' => $baseDir . '/lib/public/Accounts/IAccount.php',
'OCP\\Accounts\\IAccountManager' => $baseDir . '/lib/public/Accounts/IAccountManager.php',
'OCP\\Accounts\\IAccountProperty' => $baseDir . '/lib/public/Accounts/IAccountProperty.php',
@@ -1930,9 +1930,9 @@ return array(
'OC\\Security\\RateLimiting\\Limiter' => $baseDir . '/lib/private/Security/RateLimiting/Limiter.php',
'OC\\Security\\RemoteHostValidator' => $baseDir . '/lib/private/Security/RemoteHostValidator.php',
'OC\\Security\\SecureRandom' => $baseDir . '/lib/private/Security/SecureRandom.php',
+ 'OC\\Security\\Signature\\Db\\SignatoryMapper' => $baseDir . '/lib/private/Security/Signature/Db/SignatoryMapper.php',
'OC\\Security\\Signature\\Model\\IncomingSignedRequest' => $baseDir . '/lib/private/Security/Signature/Model/IncomingSignedRequest.php',
'OC\\Security\\Signature\\Model\\OutgoingSignedRequest' => $baseDir . '/lib/private/Security/Signature/Model/OutgoingSignedRequest.php',
- 'OC\\Security\\Signature\\Model\\Signatory' => $baseDir . '/lib/private/Security/Signature/Model/Signatory.php',
'OC\\Security\\Signature\\Model\\SignedRequest' => $baseDir . '/lib/private/Security/Signature/Model/SignedRequest.php',
'OC\\Security\\Signature\\SignatureManager' => $baseDir . '/lib/private/Security/Signature/SignatureManager.php',
'OC\\Security\\TrustedDomainHelper' => $baseDir . '/lib/private/Security/TrustedDomainHelper.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 8a5d2d3fee6..b868cd44213 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -53,6 +53,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'NCU\\Config\\Exceptions\\UnknownKeyException' => __DIR__ . '/../../..' . '/lib/unstable/Config/Exceptions/UnknownKeyException.php',
'NCU\\Config\\IUserConfig' => __DIR__ . '/../../..' . '/lib/unstable/Config/IUserConfig.php',
'NCU\\Config\\ValueType' => __DIR__ . '/../../..' . '/lib/unstable/Config/ValueType.php',
+ 'NCU\\Security\\Signature\\Enum\\SignatoryStatus' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Enum/SignatoryStatus.php',
+ 'NCU\\Security\\Signature\\Enum\\SignatoryType' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Enum/SignatoryType.php',
+ 'NCU\\Security\\Signature\\Enum\\SignatureAlgorithm' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php',
'NCU\\Security\\Signature\\Exceptions\\IdentityNotFoundException' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Exceptions/IdentityNotFoundException.php',
'NCU\\Security\\Signature\\Exceptions\\IncomingRequestException' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Exceptions/IncomingRequestException.php',
'NCU\\Security\\Signature\\Exceptions\\InvalidKeyOriginException' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Exceptions/InvalidKeyOriginException.php',
@@ -63,15 +66,12 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'NCU\\Security\\Signature\\Exceptions\\SignatureElementNotFoundException' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Exceptions/SignatureElementNotFoundException.php',
'NCU\\Security\\Signature\\Exceptions\\SignatureException' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Exceptions/SignatureException.php',
'NCU\\Security\\Signature\\Exceptions\\SignatureNotFoundException' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Exceptions/SignatureNotFoundException.php',
+ 'NCU\\Security\\Signature\\IIncomingSignedRequest' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/IIncomingSignedRequest.php',
+ 'NCU\\Security\\Signature\\IOutgoingSignedRequest' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/IOutgoingSignedRequest.php',
'NCU\\Security\\Signature\\ISignatoryManager' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/ISignatoryManager.php',
'NCU\\Security\\Signature\\ISignatureManager' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/ISignatureManager.php',
- 'NCU\\Security\\Signature\\Model\\IIncomingSignedRequest' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/IIncomingSignedRequest.php',
- 'NCU\\Security\\Signature\\Model\\IOutgoingSignedRequest' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/IOutgoingSignedRequest.php',
- 'NCU\\Security\\Signature\\Model\\ISignatory' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/ISignatory.php',
- 'NCU\\Security\\Signature\\Model\\ISignedRequest' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/ISignedRequest.php',
- 'NCU\\Security\\Signature\\Model\\SignatoryStatus' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/SignatoryStatus.php',
- 'NCU\\Security\\Signature\\Model\\SignatoryType' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/SignatoryType.php',
- 'NCU\\Security\\Signature\\SignatureAlgorithm' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/SignatureAlgorithm.php',
+ 'NCU\\Security\\Signature\\ISignedRequest' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/ISignedRequest.php',
+ 'NCU\\Security\\Signature\\Model\\Signatory' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/Signatory.php',
'OCP\\Accounts\\IAccount' => __DIR__ . '/../../..' . '/lib/public/Accounts/IAccount.php',
'OCP\\Accounts\\IAccountManager' => __DIR__ . '/../../..' . '/lib/public/Accounts/IAccountManager.php',
'OCP\\Accounts\\IAccountProperty' => __DIR__ . '/../../..' . '/lib/public/Accounts/IAccountProperty.php',
@@ -1971,9 +1971,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Security\\RateLimiting\\Limiter' => __DIR__ . '/../../..' . '/lib/private/Security/RateLimiting/Limiter.php',
'OC\\Security\\RemoteHostValidator' => __DIR__ . '/../../..' . '/lib/private/Security/RemoteHostValidator.php',
'OC\\Security\\SecureRandom' => __DIR__ . '/../../..' . '/lib/private/Security/SecureRandom.php',
+ 'OC\\Security\\Signature\\Db\\SignatoryMapper' => __DIR__ . '/../../..' . '/lib/private/Security/Signature/Db/SignatoryMapper.php',
'OC\\Security\\Signature\\Model\\IncomingSignedRequest' => __DIR__ . '/../../..' . '/lib/private/Security/Signature/Model/IncomingSignedRequest.php',
'OC\\Security\\Signature\\Model\\OutgoingSignedRequest' => __DIR__ . '/../../..' . '/lib/private/Security/Signature/Model/OutgoingSignedRequest.php',
- 'OC\\Security\\Signature\\Model\\Signatory' => __DIR__ . '/../../..' . '/lib/private/Security/Signature/Model/Signatory.php',
'OC\\Security\\Signature\\Model\\SignedRequest' => __DIR__ . '/../../..' . '/lib/private/Security/Signature/Model/SignedRequest.php',
'OC\\Security\\Signature\\SignatureManager' => __DIR__ . '/../../..' . '/lib/private/Security/Signature/SignatureManager.php',
'OC\\Security\\TrustedDomainHelper' => __DIR__ . '/../../..' . '/lib/private/Security/TrustedDomainHelper.php',
diff --git a/lib/private/OCM/Model/OCMProvider.php b/lib/private/OCM/Model/OCMProvider.php
index 95ba83882f2..32068efe3eb 100644
--- a/lib/private/OCM/Model/OCMProvider.php
+++ b/lib/private/OCM/Model/OCMProvider.php
@@ -9,8 +9,7 @@ declare(strict_types=1);
namespace OC\OCM\Model;
-use NCU\Security\Signature\Model\ISignatory;
-use OC\Security\Signature\Model\Signatory;
+use NCU\Security\Signature\Model\Signatory;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\OCM\Events\ResourceTypeRegisterEvent;
use OCP\OCM\Exceptions\OCMArgumentException;
@@ -27,7 +26,7 @@ class OCMProvider implements IOCMProvider {
private string $endPoint = '';
/** @var IOCMResource[] */
private array $resourceTypes = [];
- private ?ISignatory $signatory = null;
+ private ?Signatory $signatory = null;
private bool $emittedEvent = false;
public function __construct(
@@ -154,11 +153,11 @@ class OCMProvider implements IOCMProvider {
throw new OCMArgumentException('resource not found');
}
- public function setSignatory(ISignatory $signatory): void {
+ public function setSignatory(Signatory $signatory): void {
$this->signatory = $signatory;
}
- public function getSignatory(): ?ISignatory {
+ public function getSignatory(): ?Signatory {
return $this->signatory;
}
@@ -209,7 +208,7 @@ class OCMProvider implements IOCMProvider {
* enabled: bool,
* apiVersion: '1.0-proposal1',
* endPoint: string,
- * publicKey: ISignatory|null,
+ * publicKey: Signatory|null,
* resourceTypes: list<array{
* name: string,
* shareTypes: list<string>,
diff --git a/lib/private/OCM/OCMSignatoryManager.php b/lib/private/OCM/OCMSignatoryManager.php
index c7eb9ccda5a..909952a6b37 100644
--- a/lib/private/OCM/OCMSignatoryManager.php
+++ b/lib/private/OCM/OCMSignatoryManager.php
@@ -9,13 +9,12 @@ declare(strict_types=1);
namespace OC\OCM;
+use NCU\Security\Signature\Enum\SignatoryType;
use NCU\Security\Signature\Exceptions\IdentityNotFoundException;
use NCU\Security\Signature\ISignatoryManager;
use NCU\Security\Signature\ISignatureManager;
-use NCU\Security\Signature\Model\ISignatory;
-use NCU\Security\Signature\Model\SignatoryType;
+use NCU\Security\Signature\Model\Signatory;
use OC\Security\IdentityProof\Manager;
-use OC\Security\Signature\Model\Signatory;
use OCP\IAppConfig;
use OCP\IURLGenerator;
use OCP\OCM\Exceptions\OCMProviderException;
@@ -68,11 +67,11 @@ class OCMSignatoryManager implements ISignatoryManager {
/**
* @inheritDoc
*
- * @return ISignatory
+ * @return Signatory
* @throws IdentityNotFoundException
* @since 31.0.0
*/
- public function getLocalSignatory(): ISignatory {
+ public function getLocalSignatory(): Signatory {
/**
* TODO: manage multiple identity (external, internal, ...) to allow a limitation
* based on the requested interface (ie. only accept shares from globalscale)
@@ -125,10 +124,10 @@ class OCMSignatoryManager implements ISignatoryManager {
*
* @param string $remote
*
- * @return ISignatory|null must be NULL if no signatory is found
+ * @return Signatory|null must be NULL if no signatory is found
* @since 31.0.0
*/
- public function getRemoteSignatory(string $remote): ?ISignatory {
+ public function getRemoteSignatory(string $remote): ?Signatory {
try {
return $this->getRemoteSignatoryFromHost($remote);
} catch (OCMProviderException $e) {
@@ -142,14 +141,14 @@ class OCMSignatoryManager implements ISignatoryManager {
*
* @param string $host
*
- * @return ISignatory|null
+ * @return Signatory|null
* @throws OCMProviderException on fail to discover ocm services
* @since 31.0.0
*/
- public function getRemoteSignatoryFromHost(string $host): ?ISignatory {
+ public function getRemoteSignatoryFromHost(string $host): ?Signatory {
$ocmProvider = $this->ocmDiscoveryService->discover($host, true);
$signatory = $ocmProvider->getSignatory();
-
- return $signatory?->setType(SignatoryType::TRUSTED);
+ $signatory?->setType(SignatoryType::TRUSTED);
+ return $signatory;
}
}
diff --git a/lib/private/Security/IdentityProof/Manager.php b/lib/private/Security/IdentityProof/Manager.php
index de0b3fe6bd1..935c18bb81d 100644
--- a/lib/private/Security/IdentityProof/Manager.php
+++ b/lib/private/Security/IdentityProof/Manager.php
@@ -133,8 +133,8 @@ class Manager {
public function hasAppKey(string $app, string $name): bool {
$id = $this->generateAppKeyId($app, $name);
try {
- $this->appData->getFolder($id);
- return true;
+ $folder = $this->appData->getFolder($id);
+ return ($folder->fileExists('public') && $folder->fileExists('private'));
} catch (NotFoundException) {
return false;
}
@@ -151,11 +151,11 @@ class Manager {
public function deleteAppKey(string $app, string $name): bool {
try {
$folder = $this->appData->getFolder($this->generateAppKeyId($app, $name));
+ $folder->delete();
+ return true;
} catch (NotFoundException) {
return false;
}
- $folder->delete();
- return true;
}
private function generateAppKeyId(string $app, string $name): string {
diff --git a/lib/private/Security/Signature/Db/SignatoryMapper.php b/lib/private/Security/Signature/Db/SignatoryMapper.php
new file mode 100644
index 00000000000..47b79320548
--- /dev/null
+++ b/lib/private/Security/Signature/Db/SignatoryMapper.php
@@ -0,0 +1,114 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OC\Security\Signature\Db;
+
+use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
+use NCU\Security\Signature\Model\Signatory;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Db\QBMapper;
+use OCP\DB\Exception;
+use OCP\IDBConnection;
+
+/**
+ * @template-extends QBMapper<Signatory>
+ */
+class SignatoryMapper extends QBMapper {
+ public const TABLE = 'sec_signatory';
+
+ public function __construct(
+ IDBConnection $db,
+ ) {
+ parent::__construct($db, self::TABLE, Signatory::class);
+ }
+
+ /**
+ *
+ */
+ public function getByHost(string $host, string $account = ''): Signatory {
+ $qb = $this->db->getQueryBuilder();
+ $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('host', $qb->createNamedParameter($host)))
+ ->andWhere($qb->expr()->eq('account', $qb->createNamedParameter($account)));
+
+ try {
+ return $this->findEntity($qb);
+ } catch (DoesNotExistException) {
+ throw new SignatoryNotFoundException('no signatory found');
+ }
+ }
+
+ /**
+ */
+ public function getByKeyId(string $keyId): Signatory {
+ $qb = $this->db->getQueryBuilder();
+ $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($keyId))));
+
+ try {
+ return $this->findEntity($qb);
+ } catch (DoesNotExistException) {
+ throw new SignatoryNotFoundException('no signatory found');
+ }
+ }
+
+ /**
+ * @param string $keyId
+ *
+ * @return int
+ * @throws Exception
+ */
+ public function deleteByKeyId(string $keyId): int {
+ $qb = $this->db->getQueryBuilder();
+ $qb->delete($this->getTableName())
+ ->where($qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($keyId))));
+
+ return $qb->executeStatement();
+ }
+
+ /**
+ * @param Signatory $signatory
+ *
+ * @return int
+ */
+ public function updateMetadata(Signatory $signatory): int {
+ $qb = $this->db->getQueryBuilder();
+ $qb->update($this->getTableName())
+ ->set('metadata', $qb->createNamedParameter(json_encode($signatory->getMetadata())))
+ ->set('last_updated', $qb->createNamedParameter(time()));
+ $qb->where($qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($signatory->getKeyId()))));
+
+ return $qb->executeStatement();
+ }
+
+ /**
+ * @param Signatory $signator
+ */
+ public function updatePublicKey(Signatory $signatory): int {
+ $qb = $this->db->getQueryBuilder();
+ $qb->update($this->getTableName())
+ ->set('signatory', $qb->createNamedParameter($signatory->getPublicKey()))
+ ->set('last_updated', $qb->createNamedParameter(time()));
+ $qb->where($qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($signatory->getKeyId()))));
+
+ return $qb->executeStatement();
+ }
+
+ /**
+ * returns a hash version for keyId for better index in the database
+ *
+ * @param string $keyId
+ *
+ * @return string
+ */
+ private function hashKeyId(string $keyId): string {
+ return hash('sha256', $keyId);
+ }
+}
diff --git a/lib/private/Security/Signature/Model/IncomingSignedRequest.php b/lib/private/Security/Signature/Model/IncomingSignedRequest.php
index 77914d1e3b2..fae8b897d5b 100644
--- a/lib/private/Security/Signature/Model/IncomingSignedRequest.php
+++ b/lib/private/Security/Signature/Model/IncomingSignedRequest.php
@@ -9,14 +9,18 @@ declare(strict_types=1);
namespace OC\Security\Signature\Model;
use JsonSerializable;
+use NCU\Security\Signature\Enum\SignatureAlgorithm;
use NCU\Security\Signature\Exceptions\IdentityNotFoundException;
use NCU\Security\Signature\Exceptions\IncomingRequestException;
+use NCU\Security\Signature\Exceptions\InvalidSignatureException;
use NCU\Security\Signature\Exceptions\SignatoryException;
+use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
+use NCU\Security\Signature\Exceptions\SignatureException;
use NCU\Security\Signature\Exceptions\SignatureNotFoundException;
+use NCU\Security\Signature\IIncomingSignedRequest;
use NCU\Security\Signature\ISignatureManager;
-use NCU\Security\Signature\Model\IIncomingSignedRequest;
-use NCU\Security\Signature\Model\ISignatory;
+use NCU\Security\Signature\Model\Signatory;
use OC\Security\Signature\SignatureManager;
use OCP\IRequest;
@@ -102,27 +106,27 @@ class IncomingSignedRequest extends SignedRequest implements
* @throws IncomingRequestException
*/
private function extractSignatureHeaderFromRequest(): void {
- $sign = [];
+ $details = [];
foreach (explode(',', $this->getRequest()->getHeader('Signature')) as $entry) {
if ($entry === '' || !strpos($entry, '=')) {
continue;
}
[$k, $v] = explode('=', $entry, 2);
- preg_match('/"([^"]+)"/', $v, $var);
+ preg_match('/^"([^"]+)"$/', $v, $var);
if ($var[0] !== '') {
$v = trim($var[0], '"');
}
- $sign[$k] = $v;
+ $details[$k] = $v;
}
- $this->setSignatureElements($sign);
+ $this->setSigningElements($details);
try {
// confirm keys are in the Signature header
- $this->getSignatureElement('keyId');
- $this->getSignatureElement('headers');
- $this->setSignedSignature($this->getSignatureElement('signature'));
+ $this->getSigningElement('keyId');
+ $this->getSigningElement('headers');
+ $this->setSignature($this->getSigningElement('signature'));
} catch (SignatureElementNotFoundException $e) {
throw new IncomingRequestException($e->getMessage());
}
@@ -141,7 +145,7 @@ class IncomingSignedRequest extends SignedRequest implements
/**
* @inheritDoc
*
- * @param ISignatory $signatory
+ * @param Signatory $signatory
*
* @return $this
* @throws IdentityNotFoundException
@@ -149,7 +153,7 @@ class IncomingSignedRequest extends SignedRequest implements
* @throws SignatoryException
* @since 31.0.0
*/
- public function setSignatory(ISignatory $signatory): self {
+ public function setSignatory(Signatory $signatory): self {
$identity = \OCP\Server::get(ISignatureManager::class)->extractIdentityFromUri($signatory->getKeyId());
if ($identity !== $this->getOrigin()) {
throw new SignatoryException('keyId from provider is different from the one from signed request');
@@ -194,7 +198,31 @@ class IncomingSignedRequest extends SignedRequest implements
* @since 31.0.0
*/
public function getKeyId(): string {
- return $this->getSignatureElement('keyId');
+ return $this->getSigningElement('keyId');
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @throws SignatureException
+ * @throws SignatoryNotFoundException
+ * @since 31.0.0
+ */
+ public function verify(): void {
+ $publicKey = $this->getSignatory()->getPublicKey();
+ if ($publicKey === '') {
+ throw new SignatoryNotFoundException('empty public key');
+ }
+
+ $algorithm = SignatureAlgorithm::tryFrom($this->getSigningElement('algorithm')) ?? SignatureAlgorithm::SHA256;
+ if (openssl_verify(
+ implode("\n", $this->getSignatureData()),
+ base64_decode($this->getSignature()),
+ $publicKey,
+ $algorithm->value
+ ) !== 1) {
+ throw new InvalidSignatureException('signature issue');
+ }
}
public function jsonSerialize(): array {
diff --git a/lib/private/Security/Signature/Model/OutgoingSignedRequest.php b/lib/private/Security/Signature/Model/OutgoingSignedRequest.php
index d2d5b95e7b6..8879821a029 100644
--- a/lib/private/Security/Signature/Model/OutgoingSignedRequest.php
+++ b/lib/private/Security/Signature/Model/OutgoingSignedRequest.php
@@ -9,10 +9,12 @@ declare(strict_types=1);
namespace OC\Security\Signature\Model;
use JsonSerializable;
+use NCU\Security\Signature\Enum\SignatureAlgorithm;
+use NCU\Security\Signature\Exceptions\SignatoryException;
+use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
+use NCU\Security\Signature\IOutgoingSignedRequest;
use NCU\Security\Signature\ISignatoryManager;
use NCU\Security\Signature\ISignatureManager;
-use NCU\Security\Signature\Model\IOutgoingSignedRequest;
-use NCU\Security\Signature\SignatureAlgorithm;
use OC\Security\Signature\SignatureManager;
/**
@@ -53,7 +55,6 @@ class OutgoingSignedRequest extends SignedRequest implements
$signing = $headerList = [];
foreach ($headers as $element => $value) {
- $value = $headers[$element];
$signing[] = $element . ': ' . $value;
$headerList[] = $element;
if ($element !== '(request-target)') {
@@ -62,17 +63,17 @@ class OutgoingSignedRequest extends SignedRequest implements
}
$this->setHeaderList($headerList)
- ->setClearSignature(implode("\n", $signing));
+ ->setSignatureData($signing);
}
/**
* @inheritDoc
*
* @param string $host
- * @return IOutgoingSignedRequest
+ * @return $this
* @since 31.0.0
*/
- public function setHost(string $host): IOutgoingSignedRequest {
+ public function setHost(string $host): self {
$this->host = $host;
return $this;
}
@@ -93,10 +94,10 @@ class OutgoingSignedRequest extends SignedRequest implements
* @param string $key
* @param string|int|float $value
*
- * @return IOutgoingSignedRequest
+ * @return self
* @since 31.0.0
*/
- public function addHeader(string $key, string|int|float $value): IOutgoingSignedRequest {
+ public function addHeader(string $key, string|int|float $value): self {
$this->headers[$key] = $value;
return $this;
}
@@ -116,10 +117,10 @@ class OutgoingSignedRequest extends SignedRequest implements
*
* @param list<string> $list
*
- * @return IOutgoingSignedRequest
+ * @return self
* @since 31.0.0
*/
- public function setHeaderList(array $list): IOutgoingSignedRequest {
+ public function setHeaderList(array $list): self {
$this->headerList = $list;
return $this;
}
@@ -139,10 +140,10 @@ class OutgoingSignedRequest extends SignedRequest implements
*
* @param SignatureAlgorithm $algorithm
*
- * @return IOutgoingSignedRequest
+ * @return self
* @since 31.0.0
*/
- public function setAlgorithm(SignatureAlgorithm $algorithm): IOutgoingSignedRequest {
+ public function setAlgorithm(SignatureAlgorithm $algorithm): self {
$this->algorithm = $algorithm;
return $this;
}
@@ -157,6 +158,59 @@ class OutgoingSignedRequest extends SignedRequest implements
return $this->algorithm;
}
+ /**
+ * @inheritDoc
+ *
+ * @return self
+ * @throws SignatoryException
+ * @throws SignatoryNotFoundException
+ * @since 31.0.0
+ */
+ public function sign(): self {
+ $privateKey = $this->getSignatory()->getPrivateKey();
+ if ($privateKey === '') {
+ throw new SignatoryException('empty private key');
+ }
+
+ openssl_sign(
+ implode("\n", $this->getSignatureData()),
+ $signed,
+ $privateKey,
+ $this->getAlgorithm()->value
+ );
+
+ $this->setSignature(base64_encode($signed));
+ $this->setSigningElements(
+ [
+ 'keyId="' . $this->getSignatory()->getKeyId() . '"',
+ 'algorithm="' . $this->getAlgorithm()->value . '"',
+ 'headers="' . implode(' ', $this->getHeaderList()) . '"',
+ 'signature="' . $this->getSignature() . '"'
+ ]
+ );
+ $this->addHeader('Signature', implode(',', $this->getSigningElements()));
+
+ return $this;
+ }
+
+ /**
+ * @param string $clear
+ * @param string $privateKey
+ * @param SignatureAlgorithm $algorithm
+ *
+ * @return string
+ * @throws SignatoryException
+ */
+ private function signString(string $clear, string $privateKey, SignatureAlgorithm $algorithm): string {
+ if ($privateKey === '') {
+ throw new SignatoryException('empty private key');
+ }
+
+ openssl_sign($clear, $signed, $privateKey, $algorithm->value);
+
+ return base64_encode($signed);
+ }
+
public function jsonSerialize(): array {
return array_merge(
parent::jsonSerialize(),
diff --git a/lib/private/Security/Signature/Model/Signatory.php b/lib/private/Security/Signature/Model/Signatory.php
deleted file mode 100644
index b28d2c0415f..00000000000
--- a/lib/private/Security/Signature/Model/Signatory.php
+++ /dev/null
@@ -1,147 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-namespace OC\Security\Signature\Model;
-
-use JsonSerializable;
-use NCU\Security\Signature\Model\ISignatory;
-use NCU\Security\Signature\Model\SignatoryStatus;
-use NCU\Security\Signature\Model\SignatoryType;
-
-class Signatory implements ISignatory, JsonSerializable {
- private string $providerId = '';
- private string $account = '';
- private SignatoryType $type = SignatoryType::STATIC;
- private SignatoryStatus $status = SignatoryStatus::SYNCED;
- private array $metadata = [];
- private int $creation = 0;
- private int $lastUpdated = 0;
-
- public function __construct(
- private string $keyId,
- private readonly string $publicKey,
- private readonly string $privateKey = '',
- readonly bool $local = false,
- ) {
- // if set as local (for current instance), we apply some filters.
- if ($local) {
- // to avoid conflict with duplicate key pairs (ie generated url from the occ command), we enforce https as prefix
- if (str_starts_with($keyId, 'http://')) {
- $keyId = 'https://' . substr($keyId, 7);
- }
-
- // removing /index.php from generated url
- $path = parse_url($keyId, PHP_URL_PATH);
- if (str_starts_with($path, '/index.php/')) {
- $pos = strpos($keyId, '/index.php');
- if ($pos !== false) {
- $keyId = substr_replace($keyId, '', $pos, 10);
- }
- }
-
- $this->keyId = $keyId;
- }
- }
-
- public function setProviderId(string $providerId): self {
- $this->providerId = $providerId;
- return $this;
- }
-
- public function getProviderId(): string {
- return $this->providerId;
- }
-
- public function setAccount(string $account): self {
- $this->account = $account;
- return $this;
- }
-
- public function getAccount(): string {
- return $this->account;
- }
-
- public function getKeyId(): string {
- return $this->keyId;
- }
-
- public function getPublicKey(): string {
- return $this->publicKey;
- }
-
- public function getPrivateKey(): string {
- return $this->privateKey;
- }
-
- public function setMetadata(array $metadata): self {
- $this->metadata = $metadata;
- return $this;
- }
-
- public function getMetadata(): array {
- return $this->metadata;
- }
-
- public function setMetaValue(string $key, string|int $value): self {
- $this->metadata[$key] = $value;
- return $this;
- }
-
- public function setType(SignatoryType $type): self {
- $this->type = $type;
- return $this;
- }
- public function getType(): SignatoryType {
- return $this->type;
- }
-
- public function setStatus(SignatoryStatus $status): self {
- $this->status = $status;
- return $this;
- }
-
- public function getStatus(): SignatoryStatus {
- return $this->status;
- }
-
- public function setCreation(int $creation): self {
- $this->creation = $creation;
- return $this;
- }
-
- public function getCreation(): int {
- return $this->creation;
- }
-
- public function setLastUpdated(int $lastUpdated): self {
- $this->lastUpdated = $lastUpdated;
- return $this;
- }
-
- public function getLastUpdated(): int {
- return $this->lastUpdated;
- }
-
- public function importFromDatabase(array $row): self {
- $this->setProviderId($row['provider_id'] ?? '')
- ->setAccount($row['account'] ?? '')
- ->setMetadata(json_decode($row['metadata'], true) ?? [])
- ->setType(SignatoryType::from($row['type'] ?? 9))
- ->setStatus(SignatoryStatus::from($row['status'] ?? 1))
- ->setCreation($row['creation'] ?? 0)
- ->setLastUpdated($row['last_updated'] ?? 0);
- return $this;
- }
-
- public function jsonSerialize(): array {
- return [
- 'keyId' => $this->getKeyId(),
- 'publicKeyPem' => $this->getPublicKey()
- ];
- }
-}
diff --git a/lib/private/Security/Signature/Model/SignedRequest.php b/lib/private/Security/Signature/Model/SignedRequest.php
index 56853ebade3..dd3c1de431d 100644
--- a/lib/private/Security/Signature/Model/SignedRequest.php
+++ b/lib/private/Security/Signature/Model/SignedRequest.php
@@ -11,8 +11,8 @@ namespace OC\Security\Signature\Model;
use JsonSerializable;
use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
-use NCU\Security\Signature\Model\ISignatory;
-use NCU\Security\Signature\Model\ISignedRequest;
+use NCU\Security\Signature\ISignedRequest;
+use NCU\Security\Signature\Model\Signatory;
/**
* @inheritDoc
@@ -21,16 +21,16 @@ use NCU\Security\Signature\Model\ISignedRequest;
*/
class SignedRequest implements ISignedRequest, JsonSerializable {
private string $digest;
- private array $signatureElements = [];
- private string $clearSignature = '';
- private string $signedSignature = '';
- private ?ISignatory $signatory = null;
+ private array $signingElements = [];
+ private array $signatureData = [];
+ private string $signature = '';
+ private ?Signatory $signatory = null;
public function __construct(
private readonly string $body,
) {
// digest is created on the fly using $body
- $this->digest = 'SHA-256=' . base64_encode(hash('sha256', utf8_encode($body), true));
+ $this->digest = 'SHA-256=' . base64_encode(hash('sha256', mb_convert_encoding($body, 'UTF-8', mb_detect_encoding($body)), true));
}
/**
@@ -58,11 +58,11 @@ class SignedRequest implements ISignedRequest, JsonSerializable {
*
* @param array $elements
*
- * @return ISignedRequest
+ * @return self
* @since 31.0.0
*/
- public function setSignatureElements(array $elements): ISignedRequest {
- $this->signatureElements = $elements;
+ public function setSigningElements(array $elements): self {
+ $this->signingElements = $elements;
return $this;
}
@@ -72,8 +72,8 @@ class SignedRequest implements ISignedRequest, JsonSerializable {
* @return array
* @since 31.0.0
*/
- public function getSignatureElements(): array {
- return $this->signatureElements;
+ public function getSigningElements(): array {
+ return $this->signingElements;
}
/**
@@ -84,46 +84,47 @@ class SignedRequest implements ISignedRequest, JsonSerializable {
* @since 31.0.0
*
*/
- public function getSignatureElement(string $key): string {
- if (!array_key_exists($key, $this->signatureElements)) {
+ public function getSigningElement(string $key): string { // getSignatureDetail / getSignatureEntry() ?
+ if (!array_key_exists($key, $this->signingElements)) {
throw new SignatureElementNotFoundException('missing element ' . $key . ' in Signature header');
}
- return $this->signatureElements[$key];
+ return $this->signingElements[$key];
}
/**
* @inheritDoc
*
- * @param string $clearSignature
+ * @param array $data
*
- * @return ISignedRequest
+ * @return self
* @since 31.0.0
*/
- public function setClearSignature(string $clearSignature): ISignedRequest {
- $this->clearSignature = $clearSignature;
+ public function setSignatureData(array $data): self {
+ $this->signatureData = $data;
return $this;
}
/**
* @inheritDoc
*
- * @return string
+ * @return array
* @since 31.0.0
*/
- public function getClearSignature(): string {
- return $this->clearSignature;
+ public function getSignatureData(): array {
+ return $this->signatureData;
}
/**
* @inheritDoc
*
- * @param string $signedSignature
- * @return ISignedRequest
+ * @param string $signature
+ *
+ * @return self
* @since 31.0.0
*/
- public function setSignedSignature(string $signedSignature): ISignedRequest {
- $this->signedSignature = $signedSignature;
+ public function setSignature(string $signature): self {
+ $this->signature = $signature;
return $this;
}
@@ -133,18 +134,18 @@ class SignedRequest implements ISignedRequest, JsonSerializable {
* @return string
* @since 31.0.0
*/
- public function getSignedSignature(): string {
- return $this->signedSignature;
+ public function getSignature(): string {
+ return $this->signature;
}
/**
* @inheritDoc
*
- * @param ISignatory $signatory
- * @return ISignedRequest
+ * @param Signatory $signatory
+ * @return self
* @since 31.0.0
*/
- public function setSignatory(ISignatory $signatory): ISignedRequest {
+ public function setSignatory(Signatory $signatory): self {
$this->signatory = $signatory;
return $this;
}
@@ -152,11 +153,11 @@ class SignedRequest implements ISignedRequest, JsonSerializable {
/**
* @inheritDoc
*
- * @return ISignatory
+ * @return Signatory
* @throws SignatoryNotFoundException
* @since 31.0.0
*/
- public function getSignatory(): ISignatory {
+ public function getSignatory(): Signatory {
if ($this->signatory === null) {
throw new SignatoryNotFoundException();
}
@@ -178,9 +179,9 @@ class SignedRequest implements ISignedRequest, JsonSerializable {
return [
'body' => $this->body,
'digest' => $this->digest,
- 'signatureElements' => $this->signatureElements,
- 'clearSignature' => $this->clearSignature,
- 'signedSignature' => $this->signedSignature,
+ 'signatureElements' => $this->signingElements,
+ 'clearSignature' => $this->signatureData,
+ 'signedSignature' => $this->signature,
'signatory' => $this->signatory ?? false,
];
}
diff --git a/lib/private/Security/Signature/SignatureManager.php b/lib/private/Security/Signature/SignatureManager.php
index 2d895b465ab..6247b7901fa 100644
--- a/lib/private/Security/Signature/SignatureManager.php
+++ b/lib/private/Security/Signature/SignatureManager.php
@@ -8,6 +8,7 @@ declare(strict_types=1);
namespace OC\Security\Signature;
+use NCU\Security\Signature\Enum\SignatoryType;
use NCU\Security\Signature\Exceptions\IdentityNotFoundException;
use NCU\Security\Signature\Exceptions\IncomingRequestException;
use NCU\Security\Signature\Exceptions\InvalidKeyOriginException;
@@ -18,19 +19,16 @@ use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
use NCU\Security\Signature\Exceptions\SignatureException;
use NCU\Security\Signature\Exceptions\SignatureNotFoundException;
+use NCU\Security\Signature\IIncomingSignedRequest;
+use NCU\Security\Signature\IOutgoingSignedRequest;
use NCU\Security\Signature\ISignatoryManager;
use NCU\Security\Signature\ISignatureManager;
-use NCU\Security\Signature\Model\IIncomingSignedRequest;
-use NCU\Security\Signature\Model\IOutgoingSignedRequest;
-use NCU\Security\Signature\Model\ISignatory;
-use NCU\Security\Signature\Model\SignatoryType;
-use NCU\Security\Signature\SignatureAlgorithm;
+use NCU\Security\Signature\Model\Signatory;
+use OC\Security\Signature\Db\SignatoryMapper;
use OC\Security\Signature\Model\IncomingSignedRequest;
use OC\Security\Signature\Model\OutgoingSignedRequest;
-use OC\Security\Signature\Model\Signatory;
use OCP\DB\Exception as DBException;
use OCP\IAppConfig;
-use OCP\IDBConnection;
use OCP\IRequest;
use Psr\Log\LoggerInterface;
@@ -69,13 +67,12 @@ class SignatureManager implements ISignatureManager {
public const DATE_HEADER = 'D, d M Y H:i:s T';
public const DATE_TTL = 300;
public const SIGNATORY_TTL = 86400 * 3;
- public const TABLE_SIGNATORIES = 'sec_signatory';
public const BODY_MAXSIZE = 50000; // max size of the payload of the request
public const APPCONFIG_IDENTITY = 'security.signature.identity';
public function __construct(
private readonly IRequest $request,
- private readonly IDBConnection $connection,
+ private readonly SignatoryMapper $mapper,
private readonly IAppConfig $appConfig,
private readonly LoggerInterface $logger,
) {
@@ -107,7 +104,7 @@ class SignatureManager implements ISignatureManager {
$signedRequest = new IncomingSignedRequest($body, $this->request, $options);
try {
// we set origin based on the keyId defined in the Signature header of the request
- $signedRequest->setOrigin($this->extractIdentityFromUri($signedRequest->getSignatureElement('keyId')));
+ $signedRequest->setOrigin($this->extractIdentityFromUri($signedRequest->getSigningElement('keyId')));
} catch (IdentityNotFoundException $e) {
throw new IncomingRequestException($e->getMessage());
}
@@ -144,7 +141,7 @@ class SignatureManager implements ISignatureManager {
array $extraSignatureHeaders = [],
): void {
$request = $signedRequest->getRequest();
- $usedHeaders = explode(' ', $signedRequest->getSignatureElement('headers'));
+ $usedHeaders = explode(' ', $signedRequest->getSigningElement('headers'));
$neededHeaders = array_merge(['date', 'host', 'content-length', 'digest'], array_keys($extraSignatureHeaders));
$missingHeaders = array_diff($neededHeaders, $usedHeaders);
@@ -165,7 +162,7 @@ class SignatureManager implements ISignatureManager {
$estimated[] = $key . ': ' . $value;
}
- $signedRequest->setClearSignature(implode("\n", $estimated));
+ $signedRequest->setSignatureData($estimated);
}
/**
@@ -194,7 +191,7 @@ class SignatureManager implements ISignatureManager {
}
$signedRequest->setSignatory($knownSignatory);
- $this->verifySignedRequest($signedRequest);
+ $signedRequest->verify();
} catch (InvalidKeyOriginException $e) {
throw $e; // issue while requesting remote instance also means there is no 2nd try
} catch (SignatoryNotFoundException) {
@@ -202,7 +199,7 @@ class SignatureManager implements ISignatureManager {
// $signatoryManager), check its validity with current signature and store it
$signatory = $this->getSaneRemoteSignatory($signatoryManager, $signedRequest);
$signedRequest->setSignatory($signatory);
- $this->verifySignedRequest($signedRequest);
+ $signedRequest->verify();
$this->storeSignatory($signatory);
} catch (SignatureException) {
// if public key (from cache) is not valid, we try to refresh it (based on SignatoryType)
@@ -214,7 +211,13 @@ class SignatureManager implements ISignatureManager {
}
$signedRequest->setSignatory($signatory);
- $this->verifySignedRequest($signedRequest);
+ try {
+ $signedRequest->verify();
+ } catch (InvalidSignatureException $e) {
+ $this->logger->debug('signature issue', ['signed' => $signedRequest, 'exception' => $e]);
+ throw $e;
+ }
+
$this->storeSignatory($signatory);
}
}
@@ -247,36 +250,12 @@ class SignatureManager implements ISignatureManager {
parse_url($uri, PHP_URL_PATH) ?? '/'
);
- $this->signOutgoingRequest($signedRequest);
+ $signedRequest->sign();
return $signedRequest;
}
/**
- * signing clear version of the Signature header
- *
- * @param IOutgoingSignedRequest $signedRequest
- *
- * @throws SignatoryException
- * @throws SignatoryNotFoundException
- */
- private function signOutgoingRequest(IOutgoingSignedRequest $signedRequest): void {
- $clear = $signedRequest->getClearSignature();
- $signed = $this->signString($clear, $signedRequest->getSignatory()->getPrivateKey(), $signedRequest->getAlgorithm());
-
- $signatory = $signedRequest->getSignatory();
- $signatureElements = [
- 'keyId="' . $signatory->getKeyId() . '"',
- 'algorithm="' . $signedRequest->getAlgorithm()->value . '"',
- 'headers="' . implode(' ', $signedRequest->getHeaderList()) . '"',
- 'signature="' . $signed . '"'
- ];
-
- $signedRequest->setSignedSignature($signed);
- $signedRequest->addHeader('Signature', implode(',', $signatureElements));
- }
-
- /**
* @inheritDoc
*
* @param ISignatoryManager $signatoryManager
@@ -307,31 +286,12 @@ class SignatureManager implements ISignatureManager {
* @param string $account linked account, should be used when multiple signature can exist for the same
* host
*
- * @return ISignatory
+ * @return Signatory
* @throws SignatoryNotFoundException if entry does not exist in local database
* @since 31.0.0
*/
- public function searchSignatory(string $host, string $account = ''): ISignatory {
- $qb = $this->connection->getQueryBuilder();
- $qb->select(
- 'id', 'provider_id', 'host', 'account', 'key_id', 'key_id_sum', 'public_key', 'metadata', 'type',
- 'status', 'creation', 'last_updated'
- );
- $qb->from(self::TABLE_SIGNATORIES);
- $qb->where($qb->expr()->eq('host', $qb->createNamedParameter($host)));
- $qb->andWhere($qb->expr()->eq('account', $qb->createNamedParameter($account)));
-
- $result = $qb->executeQuery();
- $row = $result->fetch();
- $result->closeCursor();
-
- if (!$row) {
- throw new SignatoryNotFoundException('no signatory found');
- }
-
- $signature = new Signatory($row['key_id'], $row['public_key']);
-
- return $signature->importFromDatabase($row);
+ public function getSignatory(string $host, string $account = ''): Signatory {
+ return $this->mapper->getByHost($host, $account);
}
@@ -386,7 +346,7 @@ class SignatureManager implements ISignatureManager {
* @param ISignatoryManager $signatoryManager
* @param IIncomingSignedRequest $signedRequest
*
- * @return ISignatory
+ * @return Signatory
* @throws InvalidKeyOriginException
* @throws SignatoryNotFoundException
* @see ISignatoryManager::getRemoteSignatory
@@ -394,7 +354,7 @@ class SignatureManager implements ISignatureManager {
private function getSaneRemoteSignatory(
ISignatoryManager $signatoryManager,
IIncomingSignedRequest $signedRequest,
- ): ISignatory {
+ ): Signatory {
$signatory = $signatoryManager->getRemoteSignatory($signedRequest->getOrigin());
if ($signatory === null) {
throw new SignatoryNotFoundException('empty result from getRemoteSignatory');
@@ -406,107 +366,25 @@ class SignatureManager implements ISignatureManager {
} catch (SignatureElementNotFoundException) {
throw new InvalidKeyOriginException('missing keyId');
}
+ $signatory->setProviderId($signatoryManager->getProviderId());
- return $signatory->setProviderId($signatoryManager->getProviderId());
- }
-
- /**
- * @param IIncomingSignedRequest $signedRequest
- *
- * @return void
- * @throws SignatureException
- * @throws SignatoryNotFoundException
- */
- private function verifySignedRequest(IIncomingSignedRequest $signedRequest): void {
- $publicKey = $signedRequest->getSignatory()->getPublicKey();
- if ($publicKey === '') {
- throw new SignatoryNotFoundException('empty public key');
- }
-
- try {
- $this->verifyString(
- $signedRequest->getClearSignature(),
- $signedRequest->getSignedSignature(),
- $publicKey,
- SignatureAlgorithm::tryFrom($signedRequest->getSignatureElement('algorithm')) ?? SignatureAlgorithm::SHA256
- );
- } catch (InvalidSignatureException $e) {
- $this->logger->debug('signature issue', ['signed' => $signedRequest, 'exception' => $e]);
- throw $e;
- }
- }
-
- /**
- * @param string $clear
- * @param string $privateKey
- * @param SignatureAlgorithm $algorithm
- *
- * @return string
- * @throws SignatoryException
- */
- private function signString(string $clear, string $privateKey, SignatureAlgorithm $algorithm): string {
- if ($privateKey === '') {
- throw new SignatoryException('empty private key');
- }
-
- openssl_sign($clear, $signed, $privateKey, $algorithm->value);
-
- return base64_encode($signed);
- }
-
- /**
- * @param string $clear
- * @param string $encoded
- * @param string $publicKey
- * @param SignatureAlgorithm $algorithm
- *
- * @throws InvalidSignatureException
- */
- private function verifyString(
- string $clear,
- string $encoded,
- string $publicKey,
- SignatureAlgorithm $algorithm = SignatureAlgorithm::SHA256,
- ): void {
- $signed = base64_decode($encoded);
- if (openssl_verify($clear, $signed, $publicKey, $algorithm->value) !== 1) {
- throw new InvalidSignatureException('signature issue');
- }
+ return $signatory;
}
/**
* @param string $keyId
*
- * @return ISignatory
+ * @return Signatory
* @throws SignatoryNotFoundException
*/
- private function getStoredSignatory(string $keyId): ISignatory {
- $qb = $this->connection->getQueryBuilder();
- $qb->select(
- 'id', 'provider_id', 'host', 'account', 'key_id', 'key_id_sum', 'public_key', 'metadata', 'type',
- 'status', 'creation', 'last_updated'
- );
- $qb->from(self::TABLE_SIGNATORIES);
- $qb->where($qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($keyId))));
-
- $result = $qb->executeQuery();
- $row = $result->fetch();
- $result->closeCursor();
-
- if (!$row) {
- throw new SignatoryNotFoundException('no signatory found in local');
- }
-
- $signature = new Signatory($row['key_id'], $row['public_key']);
- $signature->importFromDatabase($row);
-
- return $signature;
+ private function getStoredSignatory(string $keyId): Signatory {
+ return $this->mapper->getByKeyId($keyId);
}
/**
- * @param ISignatory $signatory
+ * @param Signatory $signatory
*/
- private function storeSignatory(ISignatory $signatory): void {
+ private function storeSignatory(Signatory $signatory): void {
try {
$this->insertSignatory($signatory);
} catch (DBException $e) {
@@ -524,34 +402,20 @@ class SignatureManager implements ISignatureManager {
}
/**
- * @param ISignatory $signatory
+ * @param Signatory $signatory
* @throws DBException
*/
- private function insertSignatory(ISignatory $signatory): void {
- $qb = $this->connection->getQueryBuilder();
- $qb->insert(self::TABLE_SIGNATORIES)
- ->setValue('provider_id', $qb->createNamedParameter($signatory->getProviderId()))
- ->setValue('host', $qb->createNamedParameter($this->extractIdentityFromUri($signatory->getKeyId())))
- ->setValue('account', $qb->createNamedParameter($signatory->getAccount()))
- ->setValue('key_id', $qb->createNamedParameter($signatory->getKeyId()))
- ->setValue('key_id_sum', $qb->createNamedParameter($this->hashKeyId($signatory->getKeyId())))
- ->setValue('public_key', $qb->createNamedParameter($signatory->getPublicKey()))
- ->setValue('metadata', $qb->createNamedParameter(json_encode($signatory->getMetadata())))
- ->setValue('type', $qb->createNamedParameter($signatory->getType()->value))
- ->setValue('status', $qb->createNamedParameter($signatory->getStatus()->value))
- ->setValue('creation', $qb->createNamedParameter(time()))
- ->setValue('last_updated', $qb->createNamedParameter(time()));
-
- $qb->executeStatement();
+ private function insertSignatory(Signatory $signatory): void {
+ $this->mapper->insert($signatory);
}
/**
- * @param ISignatory $signatory
+ * @param Signatory $signatory
*
* @throws SignatoryNotFoundException
* @throws SignatoryConflictException
*/
- private function updateKnownSignatory(ISignatory $signatory): void {
+ private function updateKnownSignatory(Signatory $signatory): void {
$knownSignatory = $this->getStoredSignatory($signatory->getKeyId());
switch ($signatory->getType()) {
case SignatoryType::FORGIVABLE:
@@ -577,12 +441,12 @@ class SignatureManager implements ISignatureManager {
/**
* This is called when a remote signatory does not exist anymore
*
- * @param ISignatory|null $knownSignatory NULL is not known
+ * @param Signatory|null $knownSignatory NULL is not known
*
* @throws SignatoryConflictException
* @throws SignatoryNotFoundException
*/
- private function manageDeprecatedSignatory(?ISignatory $knownSignatory): void {
+ private function manageDeprecatedSignatory(?Signatory $knownSignatory): void {
switch ($knownSignatory?->getType()) {
case null: // unknown in local database
case SignatoryType::FORGIVABLE: // who cares ?
@@ -600,38 +464,15 @@ class SignatureManager implements ISignatureManager {
}
- private function updateSignatoryPublicKey(ISignatory $signatory): void {
- $qb = $this->connection->getQueryBuilder();
- $qb->update(self::TABLE_SIGNATORIES)
- ->set('signatory', $qb->createNamedParameter($signatory->getPublicKey()))
- ->set('last_updated', $qb->createNamedParameter(time()));
-
- $qb->where(
- $qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($signatory->getKeyId())))
- );
- $qb->executeStatement();
+ private function updateSignatoryPublicKey(Signatory $signatory): void {
+ $this->mapper->updatePublicKey($signatory);
}
- private function updateSignatoryMetadata(ISignatory $signatory): void {
- $qb = $this->connection->getQueryBuilder();
- $qb->update(self::TABLE_SIGNATORIES)
- ->set('metadata', $qb->createNamedParameter(json_encode($signatory->getMetadata())))
- ->set('last_updated', $qb->createNamedParameter(time()));
-
- $qb->where(
- $qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($signatory->getKeyId())))
- );
- $qb->executeStatement();
+ private function updateSignatoryMetadata(Signatory $signatory): void {
+ $this->mapper->updateMetadata($signatory);
}
private function deleteSignatory(string $keyId): void {
- $qb = $this->connection->getQueryBuilder();
- $qb->delete(self::TABLE_SIGNATORIES)
- ->where($qb->expr()->eq('key_id_sum', $qb->createNamedParameter($this->hashKeyId($keyId))));
- $qb->executeStatement();
- }
-
- private function hashKeyId(string $keyId): string {
- return hash('sha256', $keyId);
+ $this->mapper->deleteByKeyId($keyId);
}
}
diff --git a/lib/public/OCM/IOCMProvider.php b/lib/public/OCM/IOCMProvider.php
index dd36a1c6057..cd2a59ebd5e 100644
--- a/lib/public/OCM/IOCMProvider.php
+++ b/lib/public/OCM/IOCMProvider.php
@@ -6,11 +6,10 @@ declare(strict_types=1);
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-
namespace OCP\OCM;
use JsonSerializable;
-use NCU\Security\Signature\Model\ISignatory;
+use NCU\Security\Signature\Model\Signatory;
use OCP\OCM\Exceptions\OCMArgumentException;
use OCP\OCM\Exceptions\OCMProviderException;
@@ -124,18 +123,18 @@ interface IOCMProvider extends JsonSerializable {
/**
* store signatory (public/private key pair) to sign outgoing/incoming request
*
- * @param ISignatory $signatory
+ * @param Signatory $signatory
* @since 31.0.0
*/
- public function setSignatory(ISignatory $signatory): void;
+ public function setSignatory(Signatory $signatory): void;
/**
* signatory (public/private key pair) used to sign outgoing/incoming request
*
- * @return ISignatory|null returns null if no ISignatory available
+ * @return Signatory|null returns null if no Signatory available
* @since 31.0.0
*/
- public function getSignatory(): ?ISignatory;
+ public function getSignatory(): ?Signatory;
/**
* import data from an array
@@ -153,7 +152,7 @@ interface IOCMProvider extends JsonSerializable {
* enabled: bool,
* apiVersion: '1.0-proposal1',
* endPoint: string,
- * publicKey: ISignatory|null,
+ * publicKey: Signatory|null,
* resourceTypes: list<array{
* name: string,
* shareTypes: list<string>,
diff --git a/lib/unstable/Security/Signature/Model/SignatoryStatus.php b/lib/unstable/Security/Signature/Enum/SignatoryStatus.php
index 4174102beae..9c77cf9bbc2 100644
--- a/lib/unstable/Security/Signature/Model/SignatoryStatus.php
+++ b/lib/unstable/Security/Signature/Enum/SignatoryStatus.php
@@ -6,7 +6,7 @@ declare(strict_types=1);
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-namespace NCU\Security\Signature\Model;
+namespace NCU\Security\Signature\Enum;
/**
* current status of signatory. is it trustable or not ?
diff --git a/lib/unstable/Security/Signature/Model/SignatoryType.php b/lib/unstable/Security/Signature/Enum/SignatoryType.php
index 652bee2a970..86a766d2aa0 100644
--- a/lib/unstable/Security/Signature/Model/SignatoryType.php
+++ b/lib/unstable/Security/Signature/Enum/SignatoryType.php
@@ -3,15 +3,15 @@
declare(strict_types=1);
/**
- * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-namespace NCU\Security\Signature\Model;
+namespace NCU\Security\Signature\Enum;
/**
* type of link between local and remote instance
*
- * - FORGIVABLE = the keypair can be deleted and refreshed anytime and silently
+ * - FORGIVABLE = the keypair can be deleted and refreshed anytime; silently
* - REFRESHABLE = the keypair can be refreshed but a notice will be generated
* - TRUSTED = any changes of keypair will require human interaction, warning will be issued
* - STATIC = error will be issued on conflict, assume keypair cannot be reset.
diff --git a/lib/unstable/Security/Signature/SignatureAlgorithm.php b/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php
index c0a5a0c6c7a..94996d17bd5 100644
--- a/lib/unstable/Security/Signature/SignatureAlgorithm.php
+++ b/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php
@@ -6,7 +6,7 @@ declare(strict_types=1);
* SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-namespace NCU\Security\Signature;
+namespace NCU\Security\Signature\Enum;
/**
* list of available algorithm when signing payload
diff --git a/lib/unstable/Security/Signature/Model/IIncomingSignedRequest.php b/lib/unstable/Security/Signature/IIncomingSignedRequest.php
index 3e2ebb22a5f..7f37570533f 100644
--- a/lib/unstable/Security/Signature/Model/IIncomingSignedRequest.php
+++ b/lib/unstable/Security/Signature/IIncomingSignedRequest.php
@@ -6,10 +6,11 @@ declare(strict_types=1);
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-namespace NCU\Security\Signature\Model;
+namespace NCU\Security\Signature;
+use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
-use NCU\Security\Signature\ISignatureManager;
+use NCU\Security\Signature\Exceptions\SignatureException;
use OCP\IRequest;
/**
@@ -57,4 +58,13 @@ interface IIncomingSignedRequest extends ISignedRequest {
* @since 31.0.0
*/
public function getKeyId(): string;
+
+ /**
+ * confirm the current signed request's identity is correct
+ *
+ * @throws SignatureException
+ * @throws SignatoryNotFoundException
+ * @since 31.0.0
+ */
+ public function verify(): void;
}
diff --git a/lib/unstable/Security/Signature/Model/IOutgoingSignedRequest.php b/lib/unstable/Security/Signature/IOutgoingSignedRequest.php
index 3c9445af745..de2ab7e276d 100644
--- a/lib/unstable/Security/Signature/Model/IOutgoingSignedRequest.php
+++ b/lib/unstable/Security/Signature/IOutgoingSignedRequest.php
@@ -6,10 +6,11 @@ declare(strict_types=1);
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-namespace NCU\Security\Signature\Model;
+namespace NCU\Security\Signature;
-use NCU\Security\Signature\ISignatureManager;
-use NCU\Security\Signature\SignatureAlgorithm;
+use NCU\Security\Signature\Enum\SignatureAlgorithm;
+use NCU\Security\Signature\Exceptions\SignatoryException;
+use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
/**
* extends ISignedRequest to add info requested at the generation of the signature
@@ -23,10 +24,10 @@ interface IOutgoingSignedRequest extends ISignedRequest {
* set the host of the recipient of the request.
*
* @param string $host
- * @return IOutgoingSignedRequest
+ * @return self
* @since 31.0.0
*/
- public function setHost(string $host): IOutgoingSignedRequest;
+ public function setHost(string $host): self;
/**
* get the host of the recipient of the request.
@@ -44,10 +45,10 @@ interface IOutgoingSignedRequest extends ISignedRequest {
* @param string $key
* @param string|int|float $value
*
- * @return IOutgoingSignedRequest
+ * @return self
* @since 31.0.0
*/
- public function addHeader(string $key, string|int|float $value): IOutgoingSignedRequest;
+ public function addHeader(string $key, string|int|float $value): self;
/**
* returns list of headers value that will be added to the base request
@@ -62,10 +63,10 @@ interface IOutgoingSignedRequest extends ISignedRequest {
*
* @param list<string> $list
*
- * @return IOutgoingSignedRequest
+ * @return self
* @since 31.0.0
*/
- public function setHeaderList(array $list): IOutgoingSignedRequest;
+ public function setHeaderList(array $list): self;
/**
* returns ordered list of used headers in the Signature
@@ -80,10 +81,10 @@ interface IOutgoingSignedRequest extends ISignedRequest {
*
* @param SignatureAlgorithm $algorithm
*
- * @return IOutgoingSignedRequest
+ * @return self
* @since 31.0.0
*/
- public function setAlgorithm(SignatureAlgorithm $algorithm): IOutgoingSignedRequest;
+ public function setAlgorithm(SignatureAlgorithm $algorithm): self;
/**
* returns the algorithm set to sign the signature
@@ -92,4 +93,14 @@ interface IOutgoingSignedRequest extends ISignedRequest {
* @since 31.0.0
*/
public function getAlgorithm(): SignatureAlgorithm;
+
+ /**
+ * sign outgoing request providing a certificate that it emanate from this instance
+ *
+ * @return self
+ * @throws SignatoryException
+ * @throws SignatoryNotFoundException
+ * @since 31.0.0
+ */
+ public function sign(): self;
}
diff --git a/lib/unstable/Security/Signature/ISignatoryManager.php b/lib/unstable/Security/Signature/ISignatoryManager.php
index 19ba83a4206..20133de4c9c 100644
--- a/lib/unstable/Security/Signature/ISignatoryManager.php
+++ b/lib/unstable/Security/Signature/ISignatoryManager.php
@@ -8,7 +8,7 @@ declare(strict_types=1);
*/
namespace NCU\Security\Signature;
-use NCU\Security\Signature\Model\ISignatory;
+use NCU\Security\Signature\Model\Signatory;
/**
* ISignatoryManager contains a group of method that will help
@@ -51,10 +51,10 @@ interface ISignatoryManager {
*
* Used to sign outgoing request
*
- * @return ISignatory
+ * @return Signatory
* @since 31.0.0
*/
- public function getLocalSignatory(): ISignatory;
+ public function getLocalSignatory(): Signatory;
/**
* retrieve details and generate signatory from remote instance.
@@ -64,8 +64,8 @@ interface ISignatoryManager {
*
* @param string $remote
*
- * @return ISignatory|null must be NULL if no signatory is found
+ * @return Signatory|null must be NULL if no signatory is found
* @since 31.0.0
*/
- public function getRemoteSignatory(string $remote): ?ISignatory;
+ public function getRemoteSignatory(string $remote): ?Signatory;
}
diff --git a/lib/unstable/Security/Signature/ISignatureManager.php b/lib/unstable/Security/Signature/ISignatureManager.php
index 1969b970aa6..c614a16cd92 100644
--- a/lib/unstable/Security/Signature/ISignatureManager.php
+++ b/lib/unstable/Security/Signature/ISignatureManager.php
@@ -13,9 +13,7 @@ use NCU\Security\Signature\Exceptions\IncomingRequestException;
use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
use NCU\Security\Signature\Exceptions\SignatureException;
use NCU\Security\Signature\Exceptions\SignatureNotFoundException;
-use NCU\Security\Signature\Model\IIncomingSignedRequest;
-use NCU\Security\Signature\Model\IOutgoingSignedRequest;
-use NCU\Security\Signature\Model\ISignatory;
+use NCU\Security\Signature\Model\Signatory;
/**
* ISignatureManager is a service integrated to core that provide tools
@@ -99,11 +97,11 @@ interface ISignatureManager {
* @param string $host remote host
* @param string $account linked account, should be used when multiple signature can exist for the same host
*
- * @return ISignatory
+ * @return Signatory
* @throws SignatoryNotFoundException if entry does not exist in local database
* @since 31.0.0
*/
- public function searchSignatory(string $host, string $account = ''): ISignatory;
+ public function getSignatory(string $host, string $account = ''): Signatory;
/**
* returns a fully formatted keyId, based on a fix hostname and path
diff --git a/lib/unstable/Security/Signature/Model/ISignedRequest.php b/lib/unstable/Security/Signature/ISignedRequest.php
index 76c033970fe..6f9e143c579 100644
--- a/lib/unstable/Security/Signature/Model/ISignedRequest.php
+++ b/lib/unstable/Security/Signature/ISignedRequest.php
@@ -6,10 +6,11 @@ declare(strict_types=1);
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-namespace NCU\Security\Signature\Model;
+namespace NCU\Security\Signature;
use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
+use NCU\Security\Signature\Model\Signatory;
/**
* model that store data related to a possible signature.
@@ -42,10 +43,10 @@ interface ISignedRequest {
*
* @param array $elements
*
- * @return ISignedRequest
+ * @return self
* @since 31.0.0
*/
- public function setSignatureElements(array $elements): ISignedRequest;
+ public function setSigningElements(array $elements): self;
/**
* get the list of elements in the Signature header of the request
@@ -53,7 +54,7 @@ interface ISignedRequest {
* @return array
* @since 31.0.0
*/
- public function getSignatureElements(): array;
+ public function getSigningElements(): array;
/**
* @param string $key
@@ -62,34 +63,35 @@ interface ISignedRequest {
* @throws SignatureElementNotFoundException
* @since 31.0.0
*/
- public function getSignatureElement(string $key): string;
+ public function getSigningElement(string $key): string;
/**
- * store a clear version of the signature
+ * store data used to generate signature
*
- * @param string $clearSignature
+ * @param array $data
*
- * @return ISignedRequest
+ * @return self
* @since 31.0.0
*/
- public function setClearSignature(string $clearSignature): ISignedRequest;
+ public function setSignatureData(array $data): self;
/**
- * returns the clear version of the signature
+ * returns data used to generate signature
*
- * @return string
+ * @return array
* @since 31.0.0
*/
- public function getClearSignature(): string;
+ public function getSignatureData(): array;
/**
* set the signed version of the signature
*
- * @param string $signedSignature
- * @return ISignedRequest
+ * @param string $signature
+ *
+ * @return self
* @since 31.0.0
*/
- public function setSignedSignature(string $signedSignature): ISignedRequest;
+ public function setSignature(string $signature): self;
/**
* get the signed version of the signature
@@ -97,25 +99,25 @@ interface ISignedRequest {
* @return string
* @since 31.0.0
*/
- public function getSignedSignature(): string;
+ public function getSignature(): string;
/**
* set the signatory, containing keys and details, related to this request
*
- * @param ISignatory $signatory
- * @return ISignedRequest
+ * @param Signatory $signatory
+ * @return self
* @since 31.0.0
*/
- public function setSignatory(ISignatory $signatory): ISignedRequest;
+ public function setSignatory(Signatory $signatory): self;
/**
* get the signatory, containing keys and details, related to this request
*
- * @return ISignatory
+ * @return Signatory
* @throws SignatoryNotFoundException
* @since 31.0.0
*/
- public function getSignatory(): ISignatory;
+ public function getSignatory(): Signatory;
/**
* returns if a signatory related to this request have been found and defined
diff --git a/lib/unstable/Security/Signature/Model/ISignatory.php b/lib/unstable/Security/Signature/Model/ISignatory.php
deleted file mode 100644
index e77b77e66e5..00000000000
--- a/lib/unstable/Security/Signature/Model/ISignatory.php
+++ /dev/null
@@ -1,160 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-/**
- * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-namespace NCU\Security\Signature\Model;
-
-use NCU\Security\Signature\ISignatoryManager;
-
-/**
- * model that store keys and details related to host and in use protocol
- * mandatory details are providerId, host, keyId and public key.
- * private key is only used for local signatory, used to sign outgoing request
- *
- * the pair providerId+host is unique, meaning only one signatory can exist for each host
- * and protocol
- *
- * @since 31.0.0
- * @experimental 31.0.0
- */
-interface ISignatory {
- /**
- * unique string, related to the ISignatoryManager
- *
- * @see ISignatoryManager::getProviderId
- * @param string $providerId
- *
- * @return ISignatory
- * @since 31.0.0
- */
- public function setProviderId(string $providerId): ISignatory;
-
- /**
- * returns the provider id, unique string related to the ISignatoryManager
- *
- * @return string
- * @since 31.0.0
- */
- public function getProviderId(): string;
-
- /**
- * set account, in case your ISignatoryManager needs to manage multiple keys from same host
- *
- * @param string $account
- *
- * @return ISignatory
- * @since 31.0.0
- */
- public function setAccount(string $account): ISignatory;
-
- /**
- * return account name, empty string if not set
- *
- * @return string
- * @since 31.0.0
- */
- public function getAccount(): string;
-
- /**
- * returns key id
- *
- * @return string
- * @since 31.0.0
- */
- public function getKeyId(): string;
-
- /**
- * returns public key
- *
- * @return string
- * @since 31.0.0
- */
- public function getPublicKey(): string;
-
- /**
- * returns private key, if available
- *
- * @return string
- * @since 31.0.0
- */
- public function getPrivateKey(): string;
-
- /**
- * set metadata
- *
- * @param array $metadata
- *
- * @return ISignatory
- * @since 31.0.0
- */
- public function setMetadata(array $metadata): ISignatory;
-
- /**
- * returns metadata
- *
- * @return array
- * @since 31.0.0
- */
- public function getMetadata(): array;
-
- /**
- * update an entry in metadata
- *
- * @param string $key
- * @param string|int $value
- *
- * @return ISignatory
- * @since 31.0.0
- */
- public function setMetaValue(string $key, string|int $value): ISignatory;
-
- /**
- * set SignatoryType
- *
- * @param SignatoryType $type
- *
- * @return ISignatory
- * @since 31.0.0
- */
- public function setType(SignatoryType $type): ISignatory;
-
- /**
- * returns SignatoryType
- *
- * @return SignatoryType
- * @since 31.0.0
- */
- public function getType(): SignatoryType;
-
- /**
- * set SignatoryStatus
- *
- * @param SignatoryStatus $status
- *
- * @see SignatoryStatus
- * @return ISignatory
- * @since 31.0.0
- */
- public function setStatus(SignatoryStatus $status): ISignatory;
-
- /**
- * get SignatoryStatus
- *
- * @see SignatoryStatus
- * @return SignatoryStatus
- * @since 31.0.0
- */
- public function getStatus(): SignatoryStatus;
-
- /**
- * get last timestamp this entry has been updated
- *
- * @return int
- * @since 31.0.0
- */
- public function getLastUpdated(): int;
-}
diff --git a/lib/unstable/Security/Signature/Model/Signatory.php b/lib/unstable/Security/Signature/Model/Signatory.php
new file mode 100644
index 00000000000..621cd5ac7ee
--- /dev/null
+++ b/lib/unstable/Security/Signature/Model/Signatory.php
@@ -0,0 +1,165 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace NCU\Security\Signature\Model;
+
+use JsonSerializable;
+use NCU\Security\Signature\Enum\SignatoryStatus;
+use NCU\Security\Signature\Enum\SignatoryType;
+use OCP\AppFramework\Db\Entity;
+
+/**
+ * model that store keys and details related to host and in use protocol
+ * mandatory details are providerId, host, keyId and public key.
+ * private key is only used for local signatory, used to sign outgoing request
+ *
+ * the pair providerId+host is unique, meaning only one signatory can exist for each host
+ * and protocol
+ *
+ * @since 31.0.0
+ * @experimental 31.0.0
+ *
+ * @method void setProviderId(string $providerId)
+ * @method string getProviderId()
+ * @method string getKeyId()
+ * @method void setPublicKey(string $publicKey)
+ * @method string getPublicKey()
+ * @method void setPrivateKey(string $privateKey)
+ * @method string getPrivateKey()
+ * @method void setHost(string $host)
+ * @method string getHost()
+ * @method void setAccount(string $account)
+ * @method string getAccount()
+ * @method void setMetadata(array $metadata)
+ * @method array getMetadata()
+ * @method void setCreation(int $creation)
+ * @method int getCreation()
+ * @method void setLastUpdated(int $creation)
+ * @method int getLastUpdated()
+ */
+class Signatory extends Entity implements JsonSerializable {
+ protected string $keyId = '';
+ protected string $keyIdSum = '';
+ protected string $providerId = '';
+ protected string $host = '';
+ protected string $account = '';
+ protected int $type = 9;
+ protected int $status = 1;
+ protected array $metadata = [];
+ protected int $creation = 0;
+ protected int $lastUpdated = 0;
+
+ /**
+ * @param string $keyId
+ * @param string $publicKey
+ * @param string $privateKey
+ * @param bool $local
+ *
+ * @since 31.0.0
+ */
+ public function __construct(
+ string $keyId = '',
+ protected string $publicKey = '',
+ protected string $privateKey = '',
+ private readonly bool $local = false,
+ ) {
+ $this->addType('providerId', 'string');
+ $this->addType('host', 'string');
+ $this->addType('account', 'string');
+ $this->addType('keyId', 'string');
+ $this->addType('keyIdSum', 'string');
+ $this->addType('publicKey', 'string');
+ $this->addType('metadata', 'json');
+ $this->addType('type', 'integer');
+ $this->addType('status', 'integer');
+ $this->addType('creation', 'integer');
+ $this->addType('lastUpdated', 'integer');
+
+ $this->setKeyId($keyId);
+ }
+
+ /**
+ * @param string $keyId
+ *
+ * @since 31.0.0
+ */
+ public function setKeyId(string $keyId): void {
+ // if set as local (for current instance), we apply some filters.
+ if ($this->local) {
+ // to avoid conflict with duplicate key pairs (ie generated url from the occ command), we enforce https as prefix
+ if (str_starts_with($keyId, 'http://')) {
+ $keyId = 'https://' . substr($keyId, 7);
+ }
+
+ // removing /index.php from generated url
+ $path = parse_url($keyId, PHP_URL_PATH);
+ if (str_starts_with($path, '/index.php/')) {
+ $pos = strpos($keyId, '/index.php');
+ if ($pos !== false) {
+ $keyId = substr_replace($keyId, '', $pos, 10);
+ }
+ }
+ }
+ $this->keyId = $keyId;
+ $this->keyIdSum = hash('sha256', $keyId);
+ }
+
+ /**
+ * @param SignatoryType $type
+ * @since 31.0.0
+ */
+ public function setType(SignatoryType $type): void {
+ $this->type = $type->value;
+ }
+
+ /**
+ * @return SignatoryType
+ * @since 31.0.0
+ */
+ public function getType(): SignatoryType {
+ return SignatoryType::from($this->type);
+ }
+
+ /**
+ * @param SignatoryStatus $status
+ * @since 31.0.0
+ */
+ public function setStatus(SignatoryStatus $status): void {
+ $this->status = $status->value;
+ }
+
+ /**
+ * @return SignatoryStatus
+ * @since 31.0.0
+ */
+ public function getStatus(): SignatoryStatus {
+ return SignatoryStatus::from($this->status);
+ }
+
+ /**
+ * update an entry in metadata
+ *
+ * @param string $key
+ * @param string|int|float|bool|array $value
+ * @since 31.0.0
+ */
+ public function setMetaValue(string $key, string|int|float|bool|array $value): void {
+ $this->metadata[$key] = $value;
+ }
+
+ /**
+ * @return array
+ * @since 31.0.0
+ */
+ public function jsonSerialize(): array {
+ return [
+ 'keyId' => $this->getKeyId(),
+ 'publicKeyPem' => $this->getPublicKey()
+ ];
+ }
+}