Browse Source

fix(signed-request): removing unstable from public

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
pull/45979/head
Maxence Lange 11 months ago
parent
commit
4df3155523
  1. 4
      apps/cloud_federation_api/lib/Capabilities.php
  2. 7
      lib/private/OCM/Model/OCMProvider.php
  3. 25
      lib/private/OCM/OCMSignatoryManager.php
  4. 52
      lib/private/Security/Signature/Model/IncomingSignedRequest.php
  5. 6
      lib/private/Security/Signature/SignatureManager.php
  6. 36
      lib/public/OCM/IOCMProvider.php
  7. 3
      lib/unstable/Security/Signature/Model/Signatory.php

4
apps/cloud_federation_api/lib/Capabilities.php

@ -75,6 +75,10 @@ class Capabilities implements ICapability {
// Adding a public key to the ocm discovery
try {
if (!$this->appConfig->getValueBool('core', OCMSignatoryManager::APPCONFIG_SIGN_DISABLED, lazy: true)) {
/**
* @experimental 31.0.0
* @psalm-suppress UndefinedInterfaceMethod
*/
$this->provider->setSignatory($this->ocmSignatoryManager->getLocalSignatory());
} else {
$this->logger->debug('ocm public key feature disabled');

7
lib/private/OCM/Model/OCMProvider.php

@ -210,7 +210,10 @@ class OCMProvider implements IOCMProvider {
* enabled: bool,
* apiVersion: '1.0-proposal1',
* endPoint: string,
* publicKey: Signatory|null,
* publicKey: array{
* keyId: string,
* publicKeyPem: string
* },
* resourceTypes: list<array{
* name: string,
* shareTypes: list<string>,
@ -230,7 +233,7 @@ class OCMProvider implements IOCMProvider {
'apiVersion' => '1.0-proposal1', // deprecated, but keep it to stay compatible with old version
'version' => $this->getApiVersion(), // informative but real version
'endPoint' => $this->getEndPoint(),
'publicKey' => $this->getSignatory(),
'publicKey' => $this->getSignatory()->jsonSerialize(),
'resourceTypes' => $resourceTypes
];
}

25
lib/private/OCM/OCMSignatoryManager.php

@ -144,26 +144,17 @@ class OCMSignatoryManager implements ISignatoryManager {
*/
public function getRemoteSignatory(string $remote): ?Signatory {
try {
return $this->getRemoteSignatoryFromHost($remote);
$ocmProvider = $this->ocmDiscoveryService->discover($remote, true);
/**
* @experimental 31.0.0
* @psalm-suppress UndefinedInterfaceMethod
*/
$signatory = $ocmProvider->getSignatory();
$signatory?->setSignatoryType(SignatoryType::TRUSTED);
return $signatory;
} catch (OCMProviderException $e) {
$this->logger->warning('fail to get remote signatory', ['exception' => $e, 'remote' => $remote]);
return null;
}
}
/**
* As host is enough to generate signatory using OCMDiscoveryService
*
* @param string $host
*
* @return Signatory|null
* @throws OCMProviderException on fail to discover ocm services
* @since 31.0.0
*/
public function getRemoteSignatoryFromHost(string $host): ?Signatory {
$ocmProvider = $this->ocmDiscoveryService->discover($host, true);
$signatory = $ocmProvider->getSignatory();
$signatory?->setSignatoryType(SignatoryType::TRUSTED);
return $signatory;
}
}

52
lib/private/Security/Signature/Model/IncomingSignedRequest.php

@ -13,7 +13,6 @@ 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;
@ -53,6 +52,13 @@ class IncomingSignedRequest extends SignedRequest implements
$this->verifyHeaders();
$this->extractSignatureHeader();
$this->reconstructSignatureData();
try {
// we set origin based on the keyId defined in the Signature header of the request
$this->setOrigin(Signatory::extractIdentityFromUri($this->getSigningElement('keyId')));
} catch (IdentityNotFoundException $e) {
throw new IncomingRequestException($e->getMessage());
}
}
/**
@ -66,21 +72,22 @@ class IncomingSignedRequest extends SignedRequest implements
* @throws SignatureNotFoundException
*/
private function verifyHeaders(): void {
if ($this->request->getHeader('Signature') === '') {
throw new SignatureNotFoundException('missing Signature in header');
}
// confirm presence of date, content-length, digest and Signature
$date = $this->getRequest()->getHeader('date');
$date = $this->request->getHeader('date');
if ($date === '') {
throw new SignatureNotFoundException('missing date in header');
throw new IncomingRequestException('missing date in header');
}
$contentLength = $this->getRequest()->getHeader('content-length');
$contentLength = $this->request->getHeader('content-length');
if ($contentLength === '') {
throw new SignatureNotFoundException('missing content-length in header');
throw new IncomingRequestException('missing content-length in header');
}
$digest = $this->getRequest()->getHeader('digest');
$digest = $this->request->getHeader('digest');
if ($digest === '') {
throw new SignatureNotFoundException('missing digest in header');
}
if ($this->getRequest()->getHeader('Signature') === '') {
throw new SignatureNotFoundException('missing Signature in header');
throw new IncomingRequestException('missing digest in header');
}
// confirm date
@ -113,7 +120,7 @@ class IncomingSignedRequest extends SignedRequest implements
*/
private function extractSignatureHeader(): void {
$details = [];
foreach (explode(',', $this->getRequest()->getHeader('Signature')) as $entry) {
foreach (explode(',', $this->request->getHeader('Signature')) as $entry) {
if ($entry === '' || !strpos($entry, '=')) {
continue;
}
@ -139,6 +146,8 @@ class IncomingSignedRequest extends SignedRequest implements
}
/**
* reconstruct signature data based on signature's metadata stored in the 'Signature' header
*
* @throws SignatureException
* @throws SignatureElementNotFoundException
*/
@ -178,27 +187,6 @@ class IncomingSignedRequest extends SignedRequest implements
return $this->request;
}
/**
* @inheritDoc
*
* @param Signatory $signatory
*
* @return $this
* @throws IdentityNotFoundException
* @throws IncomingRequestException
* @throws SignatoryException
* @since 31.0.0
*/
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');
}
parent::setSignatory($signatory);
return $this;
}
/**
* @inheritDoc
*

6
lib/private/Security/Signature/SignatureManager.php

@ -102,12 +102,6 @@ class SignatureManager implements ISignatureManager {
// generate IncomingSignedRequest based on body and request
$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->getSigningElement('keyId')));
} catch (IdentityNotFoundException $e) {
throw new IncomingRequestException($e->getMessage());
}
try {
// confirm the validity of content and identity of the incoming request

36
lib/public/OCM/IOCMProvider.php

@ -9,7 +9,6 @@ declare(strict_types=1);
namespace OCP\OCM;
use JsonSerializable;
use NCU\Security\Signature\Model\Signatory;
use OCP\OCM\Exceptions\OCMArgumentException;
use OCP\OCM\Exceptions\OCMProviderException;
@ -120,21 +119,21 @@ interface IOCMProvider extends JsonSerializable {
*/
public function extractProtocolEntry(string $resourceName, string $protocol): string;
/**
* store signatory (public/private key pair) to sign outgoing/incoming request
*
* @param Signatory $signatory
* @since 31.0.0
*/
public function setSignatory(Signatory $signatory): void;
/**
* signatory (public/private key pair) used to sign outgoing/incoming request
*
* @return Signatory|null returns null if no Signatory available
* @since 31.0.0
*/
public function getSignatory(): ?Signatory;
// /**
// * store signatory (public/private key pair) to sign outgoing/incoming request
// *
// * @param Signatory $signatory
// * @experimental 31.0.0
// */
// public function setSignatory(Signatory $signatory): void;
// /**
// * signatory (public/private key pair) used to sign outgoing/incoming request
// *
// * @return Signatory|null returns null if no Signatory available
// * @experimental 31.0.0
// */
// public function getSignatory(): ?Signatory;
/**
* import data from an array
@ -152,7 +151,10 @@ interface IOCMProvider extends JsonSerializable {
* enabled: bool,
* apiVersion: '1.0-proposal1',
* endPoint: string,
* publicKey: Signatory|null,
* publicKey: array{
* keyId: string,
* publicKeyPem: string
* },
* resourceTypes: list<array{
* name: string,
* shareTypes: list<string>,

3
lib/unstable/Security/Signature/Model/Signatory.php

@ -154,6 +154,7 @@ class Signatory extends Entity implements JsonSerializable {
*/
public function setMetaValue(string $key, string|int|float|bool|array $value): void {
$this->metadata[$key] = $value;
$this->setter('metadata', [$this->metadata]);
}
/**
@ -174,7 +175,7 @@ class Signatory extends Entity implements JsonSerializable {
*
* @return string
* @throws IdentityNotFoundException if identity cannot be extracted
* @since 31.0.0
* @experimental 31.0.0
*/
public static function extractIdentityFromUri(string $uri): string {
$identity = parse_url($uri, PHP_URL_HOST);

Loading…
Cancel
Save