aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorMaxence Lange <maxence@artificial-owl.com>2024-12-02 11:30:37 -0100
committerMaxence Lange <maxence@artificial-owl.com>2024-12-04 09:30:55 -0100
commit948547bd5dbd181122333b8636f094638b036b39 (patch)
tree60c4f94ecf46f8805120c17064b0211aed01e8d0 /lib
parent4b0662005582e7a502b0de8e5e7e52f1675f3809 (diff)
downloadnextcloud-server-948547bd5dbd181122333b8636f094638b036b39.tar.gz
nextcloud-server-948547bd5dbd181122333b8636f094638b036b39.zip
fix(ocm): signatory mapper
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/composer/composer/autoload_classmap.php1
-rw-r--r--lib/composer/composer/autoload_static.php1
-rw-r--r--lib/private/OCM/Model/OCMProvider.php4
-rw-r--r--lib/private/OCM/OCMSignatoryManager.php21
-rw-r--r--lib/private/Security/Signature/Model/IncomingSignedRequest.php48
-rw-r--r--lib/private/Security/Signature/Model/OutgoingSignedRequest.php6
-rw-r--r--lib/private/Security/Signature/Model/SignedRequest.php41
-rw-r--r--lib/private/Security/Signature/SignatureManager.php55
-rw-r--r--lib/unstable/Security/Signature/Enum/DigestAlgorithm.php34
-rw-r--r--lib/unstable/Security/Signature/Enum/SignatoryStatus.php5
-rw-r--r--lib/unstable/Security/Signature/Enum/SignatoryType.php9
-rw-r--r--lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php9
-rw-r--r--lib/unstable/Security/Signature/Exceptions/IdentityNotFoundException.php1
-rw-r--r--lib/unstable/Security/Signature/Exceptions/IncomingRequestException.php1
-rw-r--r--lib/unstable/Security/Signature/Exceptions/InvalidKeyOriginException.php1
-rw-r--r--lib/unstable/Security/Signature/Exceptions/InvalidSignatureException.php1
-rw-r--r--lib/unstable/Security/Signature/Exceptions/SignatoryConflictException.php1
-rw-r--r--lib/unstable/Security/Signature/Exceptions/SignatoryException.php1
-rw-r--r--lib/unstable/Security/Signature/Exceptions/SignatoryNotFoundException.php1
-rw-r--r--lib/unstable/Security/Signature/Exceptions/SignatureElementNotFoundException.php1
-rw-r--r--lib/unstable/Security/Signature/Exceptions/SignatureException.php1
-rw-r--r--lib/unstable/Security/Signature/Exceptions/SignatureNotFoundException.php1
-rw-r--r--lib/unstable/Security/Signature/IIncomingSignedRequest.php11
-rw-r--r--lib/unstable/Security/Signature/IOutgoingSignedRequest.php19
-rw-r--r--lib/unstable/Security/Signature/ISignatoryManager.php9
-rw-r--r--lib/unstable/Security/Signature/ISignatureManager.php13
-rw-r--r--lib/unstable/Security/Signature/ISignedRequest.php44
-rw-r--r--lib/unstable/Security/Signature/Model/Signatory.php84
28 files changed, 262 insertions, 162 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 89e53c98602..a30eccfd838 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -12,6 +12,7 @@ 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\\DigestAlgorithm' => $baseDir . '/lib/unstable/Security/Signature/Enum/DigestAlgorithm.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',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index b868cd44213..9ca1852a071 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -53,6 +53,7 @@ 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\\DigestAlgorithm' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Enum/DigestAlgorithm.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',
diff --git a/lib/private/OCM/Model/OCMProvider.php b/lib/private/OCM/Model/OCMProvider.php
index 32068efe3eb..fb13b7c0f93 100644
--- a/lib/private/OCM/Model/OCMProvider.php
+++ b/lib/private/OCM/Model/OCMProvider.php
@@ -183,7 +183,9 @@ class OCMProvider implements IOCMProvider {
$this->setResourceTypes($resources);
// import details about the remote request signing public key, if available
- $signatory = new Signatory($data['publicKey']['keyId'] ?? '', $data['publicKey']['publicKeyPem'] ?? '');
+ $signatory = new Signatory();
+ $signatory->setKeyId($data['publicKey']['keyId'] ?? '');
+ $signatory->setPublicKey($data['publicKey']['publicKeyPem'] ?? '');
if ($signatory->getKeyId() !== '' && $signatory->getPublicKey() !== '') {
$this->setSignatory($signatory);
}
diff --git a/lib/private/OCM/OCMSignatoryManager.php b/lib/private/OCM/OCMSignatoryManager.php
index 909952a6b37..6b6917bcd4b 100644
--- a/lib/private/OCM/OCMSignatoryManager.php
+++ b/lib/private/OCM/OCMSignatoryManager.php
@@ -9,7 +9,9 @@ declare(strict_types=1);
namespace OC\OCM;
+use NCU\Security\Signature\Enum\DigestAlgorithm;
use NCU\Security\Signature\Enum\SignatoryType;
+use NCU\Security\Signature\Enum\SignatureAlgorithm;
use NCU\Security\Signature\Exceptions\IdentityNotFoundException;
use NCU\Security\Signature\ISignatoryManager;
use NCU\Security\Signature\ISignatureManager;
@@ -61,7 +63,15 @@ class OCMSignatoryManager implements ISignatoryManager {
* @since 31.0.0
*/
public function getOptions(): array {
- return [];
+ return [
+ 'algorithm' => SignatureAlgorithm::RSA_SHA512,
+ 'digestAlgorithm' => DigestAlgorithm::SHA512,
+ 'extraSignatureHeaders' => [],
+ 'ttl' => 300,
+ 'dateHeader' => 'D, d M Y H:i:s T',
+ 'ttlSignatory' => 86400 * 3,
+ 'bodyMaxSize' => 50000,
+ ];
}
/**
@@ -92,7 +102,12 @@ class OCMSignatoryManager implements ISignatoryManager {
}
$keyPair = $this->identityProofManager->getAppKey('core', 'ocm_external');
- return new Signatory($keyId, $keyPair->getPublic(), $keyPair->getPrivate(), local: true);
+ $signatory = new Signatory(true);
+ $signatory->setKeyId($keyId);
+ $signatory->setPublicKey($keyPair->getPublic());
+ $signatory->setPrivateKey($keyPair->getPrivate());
+ return $signatory;
+
}
/**
@@ -148,7 +163,7 @@ class OCMSignatoryManager implements ISignatoryManager {
public function getRemoteSignatoryFromHost(string $host): ?Signatory {
$ocmProvider = $this->ocmDiscoveryService->discover($host, true);
$signatory = $ocmProvider->getSignatory();
- $signatory?->setType(SignatoryType::TRUSTED);
+ $signatory?->setSignatoryType(SignatoryType::TRUSTED);
return $signatory;
}
}
diff --git a/lib/private/Security/Signature/Model/IncomingSignedRequest.php b/lib/private/Security/Signature/Model/IncomingSignedRequest.php
index fae8b897d5b..2a1aa82ac50 100644
--- a/lib/private/Security/Signature/Model/IncomingSignedRequest.php
+++ b/lib/private/Security/Signature/Model/IncomingSignedRequest.php
@@ -36,8 +36,13 @@ class IncomingSignedRequest extends SignedRequest implements
private string $origin = '';
/**
+ * @param string $body
+ * @param IRequest $request
+ * @param array $options
+ *
* @throws IncomingRequestException if incoming request is wrongly signed
- * @throws SignatureNotFoundException if signature is not fully implemented
+ * @throws SignatureException if signature is faulty
+ * @throws SignatureNotFoundException if signature is not implemented
*/
public function __construct(
string $body,
@@ -45,8 +50,9 @@ class IncomingSignedRequest extends SignedRequest implements
private readonly array $options = [],
) {
parent::__construct($body);
- $this->verifyHeadersFromRequest();
- $this->extractSignatureHeaderFromRequest();
+ $this->verifyHeaders();
+ $this->extractSignatureHeader();
+ $this->reconstructSignatureData();
}
/**
@@ -59,7 +65,7 @@ class IncomingSignedRequest extends SignedRequest implements
* @throws IncomingRequestException
* @throws SignatureNotFoundException
*/
- private function verifyHeadersFromRequest(): void {
+ private function verifyHeaders(): void {
// confirm presence of date, content-length, digest and Signature
$date = $this->getRequest()->getHeader('date');
if ($date === '') {
@@ -105,7 +111,7 @@ class IncomingSignedRequest extends SignedRequest implements
*
* @throws IncomingRequestException
*/
- private function extractSignatureHeaderFromRequest(): void {
+ private function extractSignatureHeader(): void {
$details = [];
foreach (explode(',', $this->getRequest()->getHeader('Signature')) as $entry) {
if ($entry === '' || !strpos($entry, '=')) {
@@ -133,6 +139,36 @@ class IncomingSignedRequest extends SignedRequest implements
}
/**
+ * @throws SignatureException
+ * @throws SignatureElementNotFoundException
+ */
+ private function reconstructSignatureData(): void {
+ $usedHeaders = explode(' ', $this->getSigningElement('headers'));
+ $neededHeaders = array_merge(['date', 'host', 'content-length', 'digest'],
+ array_keys($this->options['extraSignatureHeaders'] ?? []));
+
+ $missingHeaders = array_diff($neededHeaders, $usedHeaders);
+ if ($missingHeaders !== []) {
+ throw new SignatureException('missing entries in Signature.headers: ' . json_encode($missingHeaders));
+ }
+
+ $estimated = ['(request-target): ' . strtolower($this->request->getMethod()) . ' ' . $this->request->getRequestUri()];
+ foreach ($usedHeaders as $key) {
+ if ($key === '(request-target)') {
+ continue;
+ }
+ $value = (strtolower($key) === 'host') ? $this->request->getServerHost() : $this->request->getHeader($key);
+ if ($value === '') {
+ throw new SignatureException('missing header ' . $key . ' in request');
+ }
+
+ $estimated[] = $key . ': ' . $value;
+ }
+
+ $this->setSignatureData($estimated);
+ }
+
+ /**
* @inheritDoc
*
* @return IRequest
@@ -214,7 +250,7 @@ class IncomingSignedRequest extends SignedRequest implements
throw new SignatoryNotFoundException('empty public key');
}
- $algorithm = SignatureAlgorithm::tryFrom($this->getSigningElement('algorithm')) ?? SignatureAlgorithm::SHA256;
+ $algorithm = SignatureAlgorithm::tryFrom($this->getSigningElement('algorithm')) ?? SignatureAlgorithm::RSA_SHA256;
if (openssl_verify(
implode("\n", $this->getSignatureData()),
base64_decode($this->getSignature()),
diff --git a/lib/private/Security/Signature/Model/OutgoingSignedRequest.php b/lib/private/Security/Signature/Model/OutgoingSignedRequest.php
index 8879821a029..dbfac3bfd34 100644
--- a/lib/private/Security/Signature/Model/OutgoingSignedRequest.php
+++ b/lib/private/Security/Signature/Model/OutgoingSignedRequest.php
@@ -9,6 +9,7 @@ declare(strict_types=1);
namespace OC\Security\Signature\Model;
use JsonSerializable;
+use NCU\Security\Signature\Enum\DigestAlgorithm;
use NCU\Security\Signature\Enum\SignatureAlgorithm;
use NCU\Security\Signature\Exceptions\SignatoryException;
use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
@@ -42,8 +43,9 @@ class OutgoingSignedRequest extends SignedRequest implements
$options = $signatoryManager->getOptions();
$this->setHost($identity)
- ->setAlgorithm(SignatureAlgorithm::from($options['algorithm'] ?? 'sha256'))
- ->setSignatory($signatoryManager->getLocalSignatory());
+ ->setAlgorithm($options['algorithm'] ?? SignatureAlgorithm::RSA_SHA256)
+ ->setSignatory($signatoryManager->getLocalSignatory())
+ ->setDigestAlgorithm($options['digestAlgorithm'] ?? DigestAlgorithm::SHA256);
$headers = array_merge([
'(request-target)' => strtolower($method) . ' ' . $path,
diff --git a/lib/private/Security/Signature/Model/SignedRequest.php b/lib/private/Security/Signature/Model/SignedRequest.php
index dd3c1de431d..214e43e8cb3 100644
--- a/lib/private/Security/Signature/Model/SignedRequest.php
+++ b/lib/private/Security/Signature/Model/SignedRequest.php
@@ -9,6 +9,7 @@ declare(strict_types=1);
namespace OC\Security\Signature\Model;
use JsonSerializable;
+use NCU\Security\Signature\Enum\DigestAlgorithm;
use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
use NCU\Security\Signature\ISignedRequest;
@@ -20,7 +21,8 @@ use NCU\Security\Signature\Model\Signatory;
* @since 31.0.0
*/
class SignedRequest implements ISignedRequest, JsonSerializable {
- private string $digest;
+ private string $digest = '';
+ private DigestAlgorithm $digestAlgorithm = DigestAlgorithm::SHA256;
private array $signingElements = [];
private array $signatureData = [];
private string $signature = '';
@@ -29,8 +31,6 @@ class SignedRequest implements ISignedRequest, JsonSerializable {
public function __construct(
private readonly string $body,
) {
- // digest is created on the fly using $body
- $this->digest = 'SHA-256=' . base64_encode(hash('sha256', mb_convert_encoding($body, 'UTF-8', mb_detect_encoding($body)), true));
}
/**
@@ -46,10 +46,36 @@ class SignedRequest implements ISignedRequest, JsonSerializable {
/**
* @inheritDoc
*
+ * @param DigestAlgorithm $algorithm
+ *
+ * @return self
+ * @since 31.0.0
+ */
+ public function setDigestAlgorithm(DigestAlgorithm $algorithm): self {
+ return $this;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @return DigestAlgorithm
+ * @since 31.0.0
+ */
+ public function getDigestAlgorithm(): DigestAlgorithm {
+ return $this->digestAlgorithm;
+ }
+
+ /**
+ * @inheritDoc
+ *
* @return string
* @since 31.0.0
*/
public function getDigest(): string {
+ if ($this->digest === '') {
+ $this->digest = $this->digestAlgorithm->value . '=' .
+ base64_encode(hash($this->digestAlgorithm->getHashingAlgorithm(), $this->body, true));
+ }
return $this->digest;
}
@@ -178,10 +204,11 @@ class SignedRequest implements ISignedRequest, JsonSerializable {
public function jsonSerialize(): array {
return [
'body' => $this->body,
- 'digest' => $this->digest,
- 'signatureElements' => $this->signingElements,
- 'clearSignature' => $this->signatureData,
- 'signedSignature' => $this->signature,
+ 'digest' => $this->getDigest(),
+ 'digestAlgorithm' => $this->getDigestAlgorithm()->value,
+ 'signingElements' => $this->signingElements,
+ 'signatureData' => $this->signatureData,
+ 'signature' => $this->signature,
'signatory' => $this->signatory ?? false,
];
}
diff --git a/lib/private/Security/Signature/SignatureManager.php b/lib/private/Security/Signature/SignatureManager.php
index 6247b7901fa..b04d683a3b9 100644
--- a/lib/private/Security/Signature/SignatureManager.php
+++ b/lib/private/Security/Signature/SignatureManager.php
@@ -111,7 +111,6 @@ class SignatureManager implements ISignatureManager {
try {
// confirm the validity of content and identity of the incoming request
- $this->generateExpectedClearSignatureFromRequest($signedRequest, $options['extraSignatureHeaders'] ?? []);
$this->confirmIncomingRequestSignature($signedRequest, $signatoryManager, $options['ttlSignatory'] ?? self::SIGNATORY_TTL);
} catch (SignatureException $e) {
$this->logger->warning(
@@ -128,44 +127,6 @@ class SignatureManager implements ISignatureManager {
}
/**
- * generating the expected signature (clear version) sent by the remote instance
- * based on the data available in the Signature header.
- *
- * @param IIncomingSignedRequest $signedRequest
- * @param array $extraSignatureHeaders
- *
- * @throws SignatureException
- */
- private function generateExpectedClearSignatureFromRequest(
- IIncomingSignedRequest $signedRequest,
- array $extraSignatureHeaders = [],
- ): void {
- $request = $signedRequest->getRequest();
- $usedHeaders = explode(' ', $signedRequest->getSigningElement('headers'));
- $neededHeaders = array_merge(['date', 'host', 'content-length', 'digest'], array_keys($extraSignatureHeaders));
-
- $missingHeaders = array_diff($neededHeaders, $usedHeaders);
- if ($missingHeaders !== []) {
- throw new SignatureException('missing entries in Signature.headers: ' . json_encode($missingHeaders));
- }
-
- $estimated = ['(request-target): ' . strtolower($request->getMethod()) . ' ' . $request->getRequestUri()];
- foreach ($usedHeaders as $key) {
- if ($key === '(request-target)') {
- continue;
- }
- $value = (strtolower($key) === 'host') ? $request->getServerHost() : $request->getHeader($key);
- if ($value === '') {
- throw new SignatureException('missing header ' . $key . ' in request');
- }
-
- $estimated[] = $key . ': ' . $value;
- }
-
- $signedRequest->setSignatureData($estimated);
- }
-
- /**
* confirm that the Signature is signed using the correct private key, using
* clear version of the Signature and the public key linked to the keyId
*
@@ -326,17 +287,7 @@ class SignatureManager implements ISignatureManager {
* @since 31.0.0
*/
public function extractIdentityFromUri(string $uri): string {
- $identity = parse_url($uri, PHP_URL_HOST);
- $port = parse_url($uri, PHP_URL_PORT);
- if ($identity === null || $identity === false) {
- throw new IdentityNotFoundException('cannot extract identity from ' . $uri);
- }
-
- if ($port !== null && $port !== false) {
- $identity .= ':' . $port;
- }
-
- return $identity;
+ return Signatory::extractIdentityFromUri($uri);
}
/**
@@ -403,9 +354,11 @@ class SignatureManager implements ISignatureManager {
/**
* @param Signatory $signatory
- * @throws DBException
*/
private function insertSignatory(Signatory $signatory): void {
+ $time = time();
+ $signatory->setCreation($time);
+ $signatory->setLastUpdated($time);
$this->mapper->insert($signatory);
}
diff --git a/lib/unstable/Security/Signature/Enum/DigestAlgorithm.php b/lib/unstable/Security/Signature/Enum/DigestAlgorithm.php
new file mode 100644
index 00000000000..465f33fd2c3
--- /dev/null
+++ b/lib/unstable/Security/Signature/Enum/DigestAlgorithm.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace NCU\Security\Signature\Enum;
+
+/**
+ * list of available algorithm when generating digest from body
+ *
+ * @experimental 31.0.0
+ */
+enum DigestAlgorithm: string {
+ /** @experimental 31.0.0 */
+ case SHA256 = 'SHA-256';
+ /** @experimental 31.0.0 */
+ case SHA512 = 'SHA-512';
+
+ /**
+ * returns hashing algorithm to be used when generating digest
+ *
+ * @return string
+ * @experimental 31.0.0
+ */
+ public function getHashingAlgorithm(): string {
+ return match($this) {
+ self::SHA256 => 'sha256',
+ self::SHA512 => 'sha512',
+ };
+ }
+}
diff --git a/lib/unstable/Security/Signature/Enum/SignatoryStatus.php b/lib/unstable/Security/Signature/Enum/SignatoryStatus.php
index 9c77cf9bbc2..1e460aed449 100644
--- a/lib/unstable/Security/Signature/Enum/SignatoryStatus.php
+++ b/lib/unstable/Security/Signature/Enum/SignatoryStatus.php
@@ -15,11 +15,10 @@ namespace NCU\Security\Signature\Enum;
* - BROKEN = the remote instance does not use the same key pairs than previously
*
* @experimental 31.0.0
- * @since 31.0.0
*/
enum SignatoryStatus: int {
- /** @since 31.0.0 */
+ /** @experimental 31.0.0 */
case SYNCED = 1;
- /** @since 31.0.0 */
+ /** @experimental 31.0.0 */
case BROKEN = 9;
}
diff --git a/lib/unstable/Security/Signature/Enum/SignatoryType.php b/lib/unstable/Security/Signature/Enum/SignatoryType.php
index 86a766d2aa0..de3e5568479 100644
--- a/lib/unstable/Security/Signature/Enum/SignatoryType.php
+++ b/lib/unstable/Security/Signature/Enum/SignatoryType.php
@@ -17,15 +17,14 @@ namespace NCU\Security\Signature\Enum;
* - STATIC = error will be issued on conflict, assume keypair cannot be reset.
*
* @experimental 31.0.0
- * @since 31.0.0
*/
enum SignatoryType: int {
- /** @since 31.0.0 */
+ /** @experimental 31.0.0 */
case FORGIVABLE = 1; // no notice on refresh
- /** @since 31.0.0 */
+ /** @experimental 31.0.0 */
case REFRESHABLE = 4; // notice on refresh
- /** @since 31.0.0 */
+ /** @experimental 31.0.0 */
case TRUSTED = 8; // warning on refresh
- /** @since 31.0.0 */
+ /** @experimental 31.0.0 */
case STATIC = 9; // error on refresh
}
diff --git a/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php b/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php
index 94996d17bd5..5afa8a3f810 100644
--- a/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php
+++ b/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php
@@ -12,11 +12,10 @@ namespace NCU\Security\Signature\Enum;
* list of available algorithm when signing payload
*
* @experimental 31.0.0
- * @since 31.0.0
*/
enum SignatureAlgorithm: string {
- /** @since 31.0.0 */
- case SHA256 = 'sha256';
- /** @since 31.0.0 */
- case SHA512 = 'sha512';
+ /** @experimental 31.0.0 */
+ case RSA_SHA256 = 'rsa-sha256';
+ /** @experimental 31.0.0 */
+ case RSA_SHA512 = 'rsa-sha512';
}
diff --git a/lib/unstable/Security/Signature/Exceptions/IdentityNotFoundException.php b/lib/unstable/Security/Signature/Exceptions/IdentityNotFoundException.php
index 30c7f8e60a5..c8c700033e6 100644
--- a/lib/unstable/Security/Signature/Exceptions/IdentityNotFoundException.php
+++ b/lib/unstable/Security/Signature/Exceptions/IdentityNotFoundException.php
@@ -9,7 +9,6 @@ declare(strict_types=1);
namespace NCU\Security\Signature\Exceptions;
/**
- * @since 31.0.0
* @experimental 31.0.0
*/
class IdentityNotFoundException extends SignatureException {
diff --git a/lib/unstable/Security/Signature/Exceptions/IncomingRequestException.php b/lib/unstable/Security/Signature/Exceptions/IncomingRequestException.php
index d3b5c93849c..c334090fdc3 100644
--- a/lib/unstable/Security/Signature/Exceptions/IncomingRequestException.php
+++ b/lib/unstable/Security/Signature/Exceptions/IncomingRequestException.php
@@ -9,7 +9,6 @@ declare(strict_types=1);
namespace NCU\Security\Signature\Exceptions;
/**
- * @since 31.0.0
* @experimental 31.0.0
*/
class IncomingRequestException extends SignatureException {
diff --git a/lib/unstable/Security/Signature/Exceptions/InvalidKeyOriginException.php b/lib/unstable/Security/Signature/Exceptions/InvalidKeyOriginException.php
index 6e170295419..3d8fa78077f 100644
--- a/lib/unstable/Security/Signature/Exceptions/InvalidKeyOriginException.php
+++ b/lib/unstable/Security/Signature/Exceptions/InvalidKeyOriginException.php
@@ -9,7 +9,6 @@ declare(strict_types=1);
namespace NCU\Security\Signature\Exceptions;
/**
- * @since 31.0.0
* @experimental 31.0.0
*/
class InvalidKeyOriginException extends SignatureException {
diff --git a/lib/unstable/Security/Signature/Exceptions/InvalidSignatureException.php b/lib/unstable/Security/Signature/Exceptions/InvalidSignatureException.php
index dc98d9ccb84..351637ef201 100644
--- a/lib/unstable/Security/Signature/Exceptions/InvalidSignatureException.php
+++ b/lib/unstable/Security/Signature/Exceptions/InvalidSignatureException.php
@@ -9,7 +9,6 @@ declare(strict_types=1);
namespace NCU\Security\Signature\Exceptions;
/**
- * @since 31.0.0
* @experimental 31.0.0
*/
class InvalidSignatureException extends SignatureException {
diff --git a/lib/unstable/Security/Signature/Exceptions/SignatoryConflictException.php b/lib/unstable/Security/Signature/Exceptions/SignatoryConflictException.php
index c2c4d61e0de..e078071e970 100644
--- a/lib/unstable/Security/Signature/Exceptions/SignatoryConflictException.php
+++ b/lib/unstable/Security/Signature/Exceptions/SignatoryConflictException.php
@@ -9,7 +9,6 @@ declare(strict_types=1);
namespace NCU\Security\Signature\Exceptions;
/**
- * @since 31.0.0
* @experimental 31.0.0
*/
class SignatoryConflictException extends SignatoryException {
diff --git a/lib/unstable/Security/Signature/Exceptions/SignatoryException.php b/lib/unstable/Security/Signature/Exceptions/SignatoryException.php
index 0645e7b3944..92409ab3d98 100644
--- a/lib/unstable/Security/Signature/Exceptions/SignatoryException.php
+++ b/lib/unstable/Security/Signature/Exceptions/SignatoryException.php
@@ -9,7 +9,6 @@ declare(strict_types=1);
namespace NCU\Security\Signature\Exceptions;
/**
- * @since 31.0.0
* @experimental 31.0.0
*/
class SignatoryException extends SignatureException {
diff --git a/lib/unstable/Security/Signature/Exceptions/SignatoryNotFoundException.php b/lib/unstable/Security/Signature/Exceptions/SignatoryNotFoundException.php
index e956264b623..0234b3e7d5c 100644
--- a/lib/unstable/Security/Signature/Exceptions/SignatoryNotFoundException.php
+++ b/lib/unstable/Security/Signature/Exceptions/SignatoryNotFoundException.php
@@ -9,7 +9,6 @@ declare(strict_types=1);
namespace NCU\Security\Signature\Exceptions;
/**
- * @since 31.0.0
* @experimental 31.0.0
*/
class SignatoryNotFoundException extends SignatoryException {
diff --git a/lib/unstable/Security/Signature/Exceptions/SignatureElementNotFoundException.php b/lib/unstable/Security/Signature/Exceptions/SignatureElementNotFoundException.php
index f40f79410ae..ca0fa1c2194 100644
--- a/lib/unstable/Security/Signature/Exceptions/SignatureElementNotFoundException.php
+++ b/lib/unstable/Security/Signature/Exceptions/SignatureElementNotFoundException.php
@@ -9,7 +9,6 @@ declare(strict_types=1);
namespace NCU\Security\Signature\Exceptions;
/**
- * @since 31.0.0
* @experimental 31.0.0
*/
class SignatureElementNotFoundException extends SignatureException {
diff --git a/lib/unstable/Security/Signature/Exceptions/SignatureException.php b/lib/unstable/Security/Signature/Exceptions/SignatureException.php
index bcd21c9f023..12353a8e61b 100644
--- a/lib/unstable/Security/Signature/Exceptions/SignatureException.php
+++ b/lib/unstable/Security/Signature/Exceptions/SignatureException.php
@@ -11,7 +11,6 @@ namespace NCU\Security\Signature\Exceptions;
use Exception;
/**
- * @since 31.0.0
* @experimental 31.0.0
*/
class SignatureException extends Exception {
diff --git a/lib/unstable/Security/Signature/Exceptions/SignatureNotFoundException.php b/lib/unstable/Security/Signature/Exceptions/SignatureNotFoundException.php
index a1bf23710ce..f015b07673b 100644
--- a/lib/unstable/Security/Signature/Exceptions/SignatureNotFoundException.php
+++ b/lib/unstable/Security/Signature/Exceptions/SignatureNotFoundException.php
@@ -9,7 +9,6 @@ declare(strict_types=1);
namespace NCU\Security\Signature\Exceptions;
/**
- * @since 31.0.0
* @experimental 31.0.0
*/
class SignatureNotFoundException extends SignatureException {
diff --git a/lib/unstable/Security/Signature/IIncomingSignedRequest.php b/lib/unstable/Security/Signature/IIncomingSignedRequest.php
index 7f37570533f..11a2cdde868 100644
--- a/lib/unstable/Security/Signature/IIncomingSignedRequest.php
+++ b/lib/unstable/Security/Signature/IIncomingSignedRequest.php
@@ -19,14 +19,13 @@ use OCP\IRequest;
*
* @see ISignatureManager for details on signature
* @experimental 31.0.0
- * @since 31.0.0
*/
interface IIncomingSignedRequest extends ISignedRequest {
/**
* returns the base IRequest
*
* @return IRequest
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getRequest(): IRequest;
@@ -36,7 +35,7 @@ interface IIncomingSignedRequest extends ISignedRequest {
*
* @param string $origin
* @return IIncomingSignedRequest
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function setOrigin(string $origin): IIncomingSignedRequest;
@@ -45,7 +44,7 @@ interface IIncomingSignedRequest extends ISignedRequest {
* based on the keyId defined in the signature header.
*
* @return string
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getOrigin(): string;
@@ -55,7 +54,7 @@ interface IIncomingSignedRequest extends ISignedRequest {
*
* @return string
* @throws SignatureElementNotFoundException
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getKeyId(): string;
@@ -64,7 +63,7 @@ interface IIncomingSignedRequest extends ISignedRequest {
*
* @throws SignatureException
* @throws SignatoryNotFoundException
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function verify(): void;
}
diff --git a/lib/unstable/Security/Signature/IOutgoingSignedRequest.php b/lib/unstable/Security/Signature/IOutgoingSignedRequest.php
index de2ab7e276d..3901c9e555c 100644
--- a/lib/unstable/Security/Signature/IOutgoingSignedRequest.php
+++ b/lib/unstable/Security/Signature/IOutgoingSignedRequest.php
@@ -17,7 +17,6 @@ use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
*
* @see ISignatureManager for details on signature
* @experimental 31.0.0
- * @since 31.0.0
*/
interface IOutgoingSignedRequest extends ISignedRequest {
/**
@@ -25,7 +24,7 @@ interface IOutgoingSignedRequest extends ISignedRequest {
*
* @param string $host
* @return self
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function setHost(string $host): self;
@@ -35,7 +34,7 @@ interface IOutgoingSignedRequest extends ISignedRequest {
* - on outgoing request, this is the remote instance.
*
* @return string
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getHost(): string;
@@ -46,7 +45,7 @@ interface IOutgoingSignedRequest extends ISignedRequest {
* @param string|int|float $value
*
* @return self
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function addHeader(string $key, string|int|float $value): self;
@@ -54,7 +53,7 @@ interface IOutgoingSignedRequest extends ISignedRequest {
* returns list of headers value that will be added to the base request
*
* @return array
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getHeaders(): array;
@@ -64,7 +63,7 @@ interface IOutgoingSignedRequest extends ISignedRequest {
* @param list<string> $list
*
* @return self
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function setHeaderList(array $list): self;
@@ -72,7 +71,7 @@ interface IOutgoingSignedRequest extends ISignedRequest {
* returns ordered list of used headers in the Signature
*
* @return list<string>
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getHeaderList(): array;
@@ -82,7 +81,7 @@ interface IOutgoingSignedRequest extends ISignedRequest {
* @param SignatureAlgorithm $algorithm
*
* @return self
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function setAlgorithm(SignatureAlgorithm $algorithm): self;
@@ -90,7 +89,7 @@ interface IOutgoingSignedRequest extends ISignedRequest {
* returns the algorithm set to sign the signature
*
* @return SignatureAlgorithm
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getAlgorithm(): SignatureAlgorithm;
@@ -100,7 +99,7 @@ interface IOutgoingSignedRequest extends ISignedRequest {
* @return self
* @throws SignatoryException
* @throws SignatoryNotFoundException
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function sign(): self;
}
diff --git a/lib/unstable/Security/Signature/ISignatoryManager.php b/lib/unstable/Security/Signature/ISignatoryManager.php
index 20133de4c9c..e265b52f755 100644
--- a/lib/unstable/Security/Signature/ISignatoryManager.php
+++ b/lib/unstable/Security/Signature/ISignatoryManager.php
@@ -16,7 +16,6 @@ use NCU\Security\Signature\Model\Signatory;
* - confirm the authenticity of incoming signed request.
*
* @experimental 31.0.0
- * @since 31.0.0
*/
interface ISignatoryManager {
/**
@@ -26,7 +25,7 @@ interface ISignatoryManager {
* Must be unique.
*
* @return string
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getProviderId(): string;
@@ -42,7 +41,7 @@ interface ISignatoryManager {
* ]
*
* @return array
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getOptions(): array;
@@ -52,7 +51,7 @@ interface ISignatoryManager {
* Used to sign outgoing request
*
* @return Signatory
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getLocalSignatory(): Signatory;
@@ -65,7 +64,7 @@ interface ISignatoryManager {
* @param string $remote
*
* @return Signatory|null must be NULL if no signatory is found
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getRemoteSignatory(string $remote): ?Signatory;
}
diff --git a/lib/unstable/Security/Signature/ISignatureManager.php b/lib/unstable/Security/Signature/ISignatureManager.php
index c614a16cd92..b7a738d95ad 100644
--- a/lib/unstable/Security/Signature/ISignatureManager.php
+++ b/lib/unstable/Security/Signature/ISignatureManager.php
@@ -42,7 +42,6 @@ use NCU\Security\Signature\Model\Signatory;
* to ensure authenticity override protection.
*
* @experimental 31.0.0
- * @since 31.0.0
*/
interface ISignatureManager {
/**
@@ -59,7 +58,7 @@ interface ISignatureManager {
* @throws IncomingRequestException if anything looks wrong with the incoming request
* @throws SignatureNotFoundException if incoming request is not signed
* @throws SignatureException if signature could not be confirmed
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getIncomingSignedRequest(ISignatoryManager $signatoryManager, ?string $body = null): IIncomingSignedRequest;
@@ -73,7 +72,7 @@ interface ISignatureManager {
* @param string $uri needed in the signature
*
* @return IOutgoingSignedRequest
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getOutgoingSignedRequest(ISignatoryManager $signatoryManager, string $content, string $method, string $uri): IOutgoingSignedRequest;
@@ -87,7 +86,7 @@ interface ISignatureManager {
* @param string $uri needed in the signature
*
* @return array new payload to be sent, including original payload and signature elements in headers
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function signOutgoingRequestIClientPayload(ISignatoryManager $signatoryManager, array $payload, string $method, string $uri): array;
@@ -99,7 +98,7 @@ interface ISignatureManager {
*
* @return Signatory
* @throws SignatoryNotFoundException if entry does not exist in local database
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getSignatory(string $host, string $account = ''): Signatory;
@@ -110,7 +109,7 @@ interface ISignatureManager {
*
* @return string
* @throws IdentityNotFoundException if hostname is not set
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function generateKeyIdFromConfig(string $path): string;
@@ -121,7 +120,7 @@ interface ISignatureManager {
*
* @return string
* @throws IdentityNotFoundException if identity cannot be extracted
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function extractIdentityFromUri(string $uri): string;
}
diff --git a/lib/unstable/Security/Signature/ISignedRequest.php b/lib/unstable/Security/Signature/ISignedRequest.php
index 6f9e143c579..e3c77c9767a 100644
--- a/lib/unstable/Security/Signature/ISignedRequest.php
+++ b/lib/unstable/Security/Signature/ISignedRequest.php
@@ -8,6 +8,7 @@ declare(strict_types=1);
*/
namespace NCU\Security\Signature;
+use NCU\Security\Signature\Enum\DigestAlgorithm;
use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException;
use NCU\Security\Signature\Model\Signatory;
@@ -19,22 +20,39 @@ use NCU\Security\Signature\Model\Signatory;
* - to sign an outgoing request
*
* @experimental 31.0.0
- * @since 31.0.0
*/
interface ISignedRequest {
/**
* payload of the request
*
* @return string
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getBody(): string;
/**
+ * set algorithm used to generate digest
+ *
+ * @param DigestAlgorithm $algorithm
+ *
+ * @return self
+ * @experimental 31.0.0
+ */
+ public function setDigestAlgorithm(DigestAlgorithm $algorithm): self;
+
+ /**
+ * get algorithm used to generate digest
+ *
+ * @return DigestAlgorithm
+ * @experimental 31.0.0
+ */
+ public function getDigestAlgorithm(): DigestAlgorithm;
+
+ /**
* checksum of the payload of the request
*
* @return string
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getDigest(): string;
@@ -44,7 +62,7 @@ interface ISignedRequest {
* @param array $elements
*
* @return self
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function setSigningElements(array $elements): self;
@@ -52,7 +70,7 @@ interface ISignedRequest {
* get the list of elements in the Signature header of the request
*
* @return array
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getSigningElements(): array;
@@ -61,7 +79,7 @@ interface ISignedRequest {
*
* @return string
* @throws SignatureElementNotFoundException
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getSigningElement(string $key): string;
@@ -71,7 +89,7 @@ interface ISignedRequest {
* @param array $data
*
* @return self
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function setSignatureData(array $data): self;
@@ -79,7 +97,7 @@ interface ISignedRequest {
* returns data used to generate signature
*
* @return array
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getSignatureData(): array;
@@ -89,7 +107,7 @@ interface ISignedRequest {
* @param string $signature
*
* @return self
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function setSignature(string $signature): self;
@@ -97,7 +115,7 @@ interface ISignedRequest {
* get the signed version of the signature
*
* @return string
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getSignature(): string;
@@ -106,7 +124,7 @@ interface ISignedRequest {
*
* @param Signatory $signatory
* @return self
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function setSignatory(Signatory $signatory): self;
@@ -115,7 +133,7 @@ interface ISignedRequest {
*
* @return Signatory
* @throws SignatoryNotFoundException
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function getSignatory(): Signatory;
@@ -123,7 +141,7 @@ interface ISignedRequest {
* returns if a signatory related to this request have been found and defined
*
* @return bool
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function hasSignatory(): bool;
}
diff --git a/lib/unstable/Security/Signature/Model/Signatory.php b/lib/unstable/Security/Signature/Model/Signatory.php
index 621cd5ac7ee..7d11a90d24c 100644
--- a/lib/unstable/Security/Signature/Model/Signatory.php
+++ b/lib/unstable/Security/Signature/Model/Signatory.php
@@ -11,6 +11,7 @@ namespace NCU\Security\Signature\Model;
use JsonSerializable;
use NCU\Security\Signature\Enum\SignatoryStatus;
use NCU\Security\Signature\Enum\SignatoryType;
+use NCU\Security\Signature\Exceptions\IdentityNotFoundException;
use OCP\AppFramework\Db\Entity;
/**
@@ -21,18 +22,23 @@ use OCP\AppFramework\Db\Entity;
* 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 setKeyIdSum(string $keyIdSum)
+ * @method string getKeyIdSum()
* @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 int getType()
+ * @method void setType(int $type)
+ * @method int getStatus()
+ * @method void setStatus(int $status)
* @method void setAccount(string $account)
* @method string getAccount()
* @method void setMetadata(array $metadata)
@@ -41,12 +47,15 @@ use OCP\AppFramework\Db\Entity;
* @method int getCreation()
* @method void setLastUpdated(int $creation)
* @method int getLastUpdated()
+ * @psalm-suppress PropertyNotSetInConstructor
*/
class Signatory extends Entity implements JsonSerializable {
protected string $keyId = '';
protected string $keyIdSum = '';
protected string $providerId = '';
protected string $host = '';
+ protected string $publicKey = '';
+ protected string $privateKey = '';
protected string $account = '';
protected int $type = 9;
protected int $status = 1;
@@ -55,17 +64,11 @@ class Signatory extends Entity implements JsonSerializable {
protected int $lastUpdated = 0;
/**
- * @param string $keyId
- * @param string $publicKey
- * @param string $privateKey
- * @param bool $local
+ * @param bool $local only set to TRUE when managing local signatory
*
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function __construct(
- string $keyId = '',
- protected string $publicKey = '',
- protected string $privateKey = '',
private readonly bool $local = false,
) {
$this->addType('providerId', 'string');
@@ -79,14 +82,13 @@ class Signatory extends Entity implements JsonSerializable {
$this->addType('status', 'integer');
$this->addType('creation', 'integer');
$this->addType('lastUpdated', 'integer');
-
- $this->setKeyId($keyId);
}
/**
* @param string $keyId
*
- * @since 31.0.0
+ * @experimental 31.0.0
+ * @throws IdentityNotFoundException if identity cannot be extracted from keyId
*/
public function setKeyId(string $keyId): void {
// if set as local (for current instance), we apply some filters.
@@ -105,40 +107,42 @@ class Signatory extends Entity implements JsonSerializable {
}
}
}
- $this->keyId = $keyId;
- $this->keyIdSum = hash('sha256', $keyId);
+ $this->setter('keyId', [$keyId]); // needed to trigger the update in database
+ $this->setKeyIdSum(hash('sha256', $keyId));
+
+ $this->setHost(self::extractIdentityFromUri($this->getKeyId()));
}
/**
* @param SignatoryType $type
- * @since 31.0.0
+ * @experimental 31.0.0
*/
- public function setType(SignatoryType $type): void {
- $this->type = $type->value;
+ public function setSignatoryType(SignatoryType $type): void {
+ $this->setType($type->value);
}
/**
* @return SignatoryType
- * @since 31.0.0
+ * @experimental 31.0.0
*/
- public function getType(): SignatoryType {
- return SignatoryType::from($this->type);
+ public function getSignatoryType(): SignatoryType {
+ return SignatoryType::from($this->getType());
}
/**
* @param SignatoryStatus $status
- * @since 31.0.0
+ * @experimental 31.0.0
*/
- public function setStatus(SignatoryStatus $status): void {
- $this->status = $status->value;
+ public function setSignatoryStatus(SignatoryStatus $status): void {
+ $this->setStatus($status->value);
}
/**
* @return SignatoryStatus
- * @since 31.0.0
+ * @experimental 31.0.0
*/
- public function getStatus(): SignatoryStatus {
- return SignatoryStatus::from($this->status);
+ public function getSignatoryStatus(): SignatoryStatus {
+ return SignatoryStatus::from($this->getStatus());
}
/**
@@ -146,7 +150,7 @@ class Signatory extends Entity implements JsonSerializable {
*
* @param string $key
* @param string|int|float|bool|array $value
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function setMetaValue(string $key, string|int|float|bool|array $value): void {
$this->metadata[$key] = $value;
@@ -154,7 +158,7 @@ class Signatory extends Entity implements JsonSerializable {
/**
* @return array
- * @since 31.0.0
+ * @experimental 31.0.0
*/
public function jsonSerialize(): array {
return [
@@ -162,4 +166,28 @@ class Signatory extends Entity implements JsonSerializable {
'publicKeyPem' => $this->getPublicKey()
];
}
+
+ /**
+ * static is needed to make this easily callable from outside the model
+ *
+ * @param string $uri
+ *
+ * @return string
+ * @throws IdentityNotFoundException if identity cannot be extracted
+ * @since 31.0.0
+ */
+ public static function extractIdentityFromUri(string $uri): string {
+ $identity = parse_url($uri, PHP_URL_HOST);
+ $port = parse_url($uri, PHP_URL_PORT);
+ if ($identity === null || $identity === false) {
+ throw new IdentityNotFoundException('cannot extract identity from ' . $uri);
+ }
+
+ if ($port !== null && $port !== false) {
+ $identity .= ':' . $port;
+ }
+
+ return $identity;
+ }
+
}