Skip to content

Commit

Permalink
fix(ocm): switching to IdentityProof
Browse files Browse the repository at this point in the history
Signed-off-by: Maxence Lange <[email protected]>
  • Loading branch information
ArtificialOwl committed Nov 17, 2024
1 parent 14b8a00 commit 5912b44
Show file tree
Hide file tree
Showing 22 changed files with 120 additions and 646 deletions.
4 changes: 2 additions & 2 deletions apps/cloud_federation_api/lib/Capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/
namespace OCA\CloudFederationAPI;

use NCU\Security\PublicPrivateKeyPairs\Exceptions\KeyPairException;
use NCU\Security\Signature\Exceptions\IdentityNotFoundException;
use NCU\Security\Signature\Exceptions\SignatoryException;
use OC\OCM\OCMSignatoryManager;
use OCP\Capabilities\ICapability;
Expand Down Expand Up @@ -79,7 +79,7 @@ public function getCapabilities() {
} else {
$this->logger->debug('ocm public key feature disabled');
}
} catch (SignatoryException|KeyPairException $e) {
} catch (SignatoryException|IdentityNotFoundException $e) {
$this->logger->warning('cannot generate local signatory', ['exception' => $e]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
namespace OCA\CloudFederationAPI\Controller;

use NCU\Security\Signature\Exceptions\IdentityNotFoundException;
use NCU\Security\Signature\Exceptions\IncomingRequestException;
use NCU\Security\Signature\Exceptions\SignatoryNotFoundException;
use NCU\Security\Signature\Exceptions\SignatureException;
Expand Down Expand Up @@ -427,16 +428,10 @@ private function getHostFromFederationId(string $entry): string {
}
[, $rightPart] = explode('@', $entry, 2);

$host = parse_url($rightPart, PHP_URL_HOST);
$port = parse_url($rightPart, PHP_URL_PORT);
if ($port !== null && $port !== false) {
$host .= ':' . $port;
}

if (is_string($host) && $host !== '') {
return $host;
try {
return $this->signatureManager->extractIdentityFromUri($rightPart);
} catch (IdentityNotFoundException) {
throw new IncomingRequestException('invalid host within federation id: ' . $entry);
}

throw new IncomingRequestException('host is empty');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ Feature: cleanup-remote-storage
# server may have its own /textfile0.txt" file)
And User "user1" copies file "/textfile0.txt" to "/remote-share.txt"
And User "user1" from server "REMOTE" shares "/remote-share.txt" with user "user0" from server "LOCAL"
And As an "user1"
And sending "GET" to "/apps/files_sharing/api/v1/shares"
And the list of returned shares has 1 shares
And Using server "LOCAL"
# Accept and download the file to ensure that a storage is created for the
# federated share
Expand Down
7 changes: 0 additions & 7 deletions lib/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@

return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'NCU\\Security\\PublicPrivateKeyPairs\\Exceptions\\KeyPairConflictException' => $baseDir . '/lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairConflictException.php',
'NCU\\Security\\PublicPrivateKeyPairs\\Exceptions\\KeyPairException' => $baseDir . '/lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairException.php',
'NCU\\Security\\PublicPrivateKeyPairs\\Exceptions\\KeyPairNotFoundException' => $baseDir . '/lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairNotFoundException.php',
'NCU\\Security\\PublicPrivateKeyPairs\\IKeyPairManager' => $baseDir . '/lib/unstable/Security/PublicPrivateKeyPairs/IKeyPairManager.php',
'NCU\\Security\\PublicPrivateKeyPairs\\Model\\IKeyPair' => $baseDir . '/lib/unstable/Security/PublicPrivateKeyPairs/Model/IKeyPair.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\\IncomingRequestNotFoundException' => $baseDir . '/lib/unstable/Security/Signature/Exceptions/IncomingRequestNotFoundException.php',
Expand Down Expand Up @@ -1920,8 +1915,6 @@
'OC\\Security\\Ip\\Range' => $baseDir . '/lib/private/Security/Ip/Range.php',
'OC\\Security\\Ip\\RemoteAddress' => $baseDir . '/lib/private/Security/Ip/RemoteAddress.php',
'OC\\Security\\Normalizer\\IpAddress' => $baseDir . '/lib/private/Security/Normalizer/IpAddress.php',
'OC\\Security\\PublicPrivateKeyPairs\\KeyPairManager' => $baseDir . '/lib/private/Security/PublicPrivateKeyPairs/KeyPairManager.php',
'OC\\Security\\PublicPrivateKeyPairs\\Model\\KeyPair' => $baseDir . '/lib/private/Security/PublicPrivateKeyPairs/Model/KeyPair.php',
'OC\\Security\\RateLimiting\\Backend\\DatabaseBackend' => $baseDir . '/lib/private/Security/RateLimiting/Backend/DatabaseBackend.php',
'OC\\Security\\RateLimiting\\Backend\\IBackend' => $baseDir . '/lib/private/Security/RateLimiting/Backend/IBackend.php',
'OC\\Security\\RateLimiting\\Backend\\MemoryCacheBackend' => $baseDir . '/lib/private/Security/RateLimiting/Backend/MemoryCacheBackend.php',
Expand Down
7 changes: 0 additions & 7 deletions lib/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2

public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'NCU\\Security\\PublicPrivateKeyPairs\\Exceptions\\KeyPairConflictException' => __DIR__ . '/../../..' . '/lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairConflictException.php',
'NCU\\Security\\PublicPrivateKeyPairs\\Exceptions\\KeyPairException' => __DIR__ . '/../../..' . '/lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairException.php',
'NCU\\Security\\PublicPrivateKeyPairs\\Exceptions\\KeyPairNotFoundException' => __DIR__ . '/../../..' . '/lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairNotFoundException.php',
'NCU\\Security\\PublicPrivateKeyPairs\\IKeyPairManager' => __DIR__ . '/../../..' . '/lib/unstable/Security/PublicPrivateKeyPairs/IKeyPairManager.php',
'NCU\\Security\\PublicPrivateKeyPairs\\Model\\IKeyPair' => __DIR__ . '/../../..' . '/lib/unstable/Security/PublicPrivateKeyPairs/Model/IKeyPair.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\\IncomingRequestNotFoundException' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Exceptions/IncomingRequestNotFoundException.php',
Expand Down Expand Up @@ -1961,8 +1956,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Security\\Ip\\Range' => __DIR__ . '/../../..' . '/lib/private/Security/Ip/Range.php',
'OC\\Security\\Ip\\RemoteAddress' => __DIR__ . '/../../..' . '/lib/private/Security/Ip/RemoteAddress.php',
'OC\\Security\\Normalizer\\IpAddress' => __DIR__ . '/../../..' . '/lib/private/Security/Normalizer/IpAddress.php',
'OC\\Security\\PublicPrivateKeyPairs\\KeyPairManager' => __DIR__ . '/../../..' . '/lib/private/Security/PublicPrivateKeyPairs/KeyPairManager.php',
'OC\\Security\\PublicPrivateKeyPairs\\Model\\KeyPair' => __DIR__ . '/../../..' . '/lib/private/Security/PublicPrivateKeyPairs/Model/KeyPair.php',
'OC\\Security\\RateLimiting\\Backend\\DatabaseBackend' => __DIR__ . '/../../..' . '/lib/private/Security/RateLimiting/Backend/DatabaseBackend.php',
'OC\\Security\\RateLimiting\\Backend\\IBackend' => __DIR__ . '/../../..' . '/lib/private/Security/RateLimiting/Backend/IBackend.php',
'OC\\Security\\RateLimiting\\Backend\\MemoryCacheBackend' => __DIR__ . '/../../..' . '/lib/private/Security/RateLimiting/Backend/MemoryCacheBackend.php',
Expand Down
109 changes: 45 additions & 64 deletions lib/private/Federation/CloudFederationProviderManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use OCP\Federation\ICloudFederationProviderManager;
use OCP\Federation\ICloudFederationShare;
use OCP\Federation\ICloudIdManager;
use OCP\Http\Client\IClient;
use OCP\Http\Client\IClientService;
use OCP\Http\Client\IResponse;
use OCP\IAppConfig;
Expand Down Expand Up @@ -105,25 +106,11 @@ public function getCloudFederationProvider($resourceType) {
public function sendShare(ICloudFederationShare $share) {
$cloudID = $this->cloudIdManager->resolveCloudId($share->getShareWith());
try {
$ocmProvider = $this->discoveryService->discover($cloudID->getRemote());
} catch (OCMProviderException $e) {
return false;
}

$client = $this->httpClientService->newClient();
try {
// signing the payload using OCMSignatoryManager before initializing the request
$uri = $ocmProvider->getEndPoint() . '/shares';
$payload = array_merge($this->getDefaultRequestOptions(), ['body' => json_encode($share->getShare())]);
if (!$this->appConfig->getValueBool('core', OCMSignatoryManager::APPCONFIG_SIGN_DISABLED, lazy: true)) {
$signedPayload = $this->signatureManager->signOutgoingRequestIClientPayload(
$this->signatoryManager,
$payload,
'post', $uri
);
try {
$response = $this->postOcmPayload($cloudID->getRemote(), '/shares', json_encode($share->getShare()));
} catch (OCMProviderException) {
return false;
}
$response = $client->post($uri, $signedPayload ?? $payload);

if ($response->getStatusCode() === Http::STATUS_CREATED) {
$result = json_decode($response->getBody(), true);
return (is_array($result)) ? $result : [];
Expand All @@ -149,22 +136,9 @@ public function sendShare(ICloudFederationShare $share) {
*/
public function sendCloudShare(ICloudFederationShare $share): IResponse {
$cloudID = $this->cloudIdManager->resolveCloudId($share->getShareWith());
$ocmProvider = $this->discoveryService->discover($cloudID->getRemote());

$client = $this->httpClientService->newClient();
try {
// signing the payload using OCMSignatoryManager before initializing the request
$uri = $ocmProvider->getEndPoint() . '/shares';
$payload = array_merge($this->getDefaultRequestOptions(), ['body' => json_encode($share->getShare())]);
if (!$this->appConfig->getValueBool('core', OCMSignatoryManager::APPCONFIG_SIGN_DISABLED, lazy: true)) {
$signedPayload = $this->signatureManager->signOutgoingRequestIClientPayload(
$this->signatoryManager,
$payload,
'post', $uri
);
}

return $client->post($uri, $signedPayload ?? $payload);
return $this->postOcmPayload($cloudID->getRemote(), '/shares', json_encode($share->getShare()), $client);
} catch (\Throwable $e) {
$this->logger->error('Error while sending share to federation server: ' . $e->getMessage(), ['exception' => $e]);
try {
Expand All @@ -183,26 +157,11 @@ public function sendCloudShare(ICloudFederationShare $share): IResponse {
*/
public function sendNotification($url, ICloudFederationNotification $notification) {
try {
$ocmProvider = $this->discoveryService->discover($url);
} catch (OCMProviderException $e) {
return false;
}

$client = $this->httpClientService->newClient();
try {

// signing the payload using OCMSignatoryManager before initializing the request
$uri = $ocmProvider->getEndPoint() . '/notifications';
$payload = array_merge($this->getDefaultRequestOptions(), ['body' => json_encode($notification->getMessage())]);
if (!$this->appConfig->getValueBool('core', OCMSignatoryManager::APPCONFIG_SIGN_DISABLED, lazy: true)) {
$signedPayload = $this->signatureManager->signOutgoingRequestIClientPayload(
$this->signatoryManager,
$payload,
'post', $uri
);
try {
$response = $this->postOcmPayload($url, '/notifications', json_encode($notification->getMessage()));
} catch (OCMProviderException) {
return false;
}
$response = $client->post($uri, $signedPayload ?? $payload);

if ($response->getStatusCode() === Http::STATUS_CREATED) {
$result = json_decode($response->getBody(), true);
return (is_array($result)) ? $result : [];
Expand All @@ -222,21 +181,9 @@ public function sendNotification($url, ICloudFederationNotification $notificatio
* @throws OCMProviderException
*/
public function sendCloudNotification(string $url, ICloudFederationNotification $notification): IResponse {
$ocmProvider = $this->discoveryService->discover($url);

$client = $this->httpClientService->newClient();
try {
// signing the payload using OCMSignatoryManager before initializing the request
$uri = $ocmProvider->getEndPoint() . '/notifications';
$payload = array_merge($this->getDefaultRequestOptions(), ['body' => json_encode($notification->getMessage())]);
if (!$this->appConfig->getValueBool('core', OCMSignatoryManager::APPCONFIG_SIGN_DISABLED, lazy: true)) {
$signedPayload = $this->signatureManager->signOutgoingRequestIClientPayload(
$this->signatoryManager,
$payload,
'post', $uri
);
}
return $client->post($uri, $signedPayload ?? $payload);
return $this->postOcmPayload($url, '/notifications', json_encode($notification->getMessage()), $client);
} catch (\Throwable $e) {
$this->logger->error('Error while sending notification to federation server: ' . $e->getMessage(), ['exception' => $e]);
try {
Expand All @@ -256,6 +203,40 @@ public function isReady() {
return $this->appManager->isEnabledForUser('cloud_federation_api');
}

/**
* @param string $cloudId
* @param string $uri
* @param string $payload
*
* @return IResponse
* @throws OCMProviderException
*/
private function postOcmPayload(string $cloudId, string $uri, string $payload, ?IClient $client = null): IResponse {
$ocmProvider = $this->discoveryService->discover($cloudId);
$uri = $ocmProvider->getEndPoint() . '/' . ltrim($uri, '/');
$client = $client ?? $this->httpClientService->newClient();
return $client->post($uri, $this->prepareOcmPayload($uri, $payload));
}

/**
* @param string $uri
* @param string $payload
*
* @return array
*/
private function prepareOcmPayload(string $uri, string $payload): array {
$payload = array_merge($this->getDefaultRequestOptions(), ['body' => $payload]);
if (!$this->appConfig->getValueBool('core', OCMSignatoryManager::APPCONFIG_SIGN_DISABLED, lazy: true)) {
$signedPayload = $this->signatureManager->signOutgoingRequestIClientPayload(
$this->signatoryManager,
$payload,
'post', $uri
);
}

return $signedPayload ?? $payload;
}

private function getDefaultRequestOptions(): array {
return [
'headers' => ['content-type' => 'application/json'],
Expand Down
7 changes: 0 additions & 7 deletions lib/private/Files/Storage/DAV.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ class DAV extends Common {
protected $httpClientService;
/** @var ICertificateManager */
protected $certManager;
protected bool $verify = true;
protected LoggerInterface $logger;
protected IEventLogger $eventLogger;
protected IMimeTypeDetector $mimeTypeDetector;
Expand Down Expand Up @@ -104,7 +103,6 @@ public function __construct(array $parameters) {
if (isset($parameters['authType'])) {
$this->authType = $parameters['authType'];
}
$this->verify = (($parameters['verify'] ?? true) !== false);
if (isset($parameters['secure'])) {
if (is_string($parameters['secure'])) {
$this->secure = ($parameters['secure'] === 'true');
Expand Down Expand Up @@ -164,11 +162,6 @@ protected function init(): void {
}
}

if (!$this->verify) {
$this->client->addCurlSetting(CURLOPT_SSL_VERIFYHOST, 0);
$this->client->addCurlSetting(CURLOPT_SSL_VERIFYPEER, false);
}

$lastRequestStart = 0;
$this->client->on('beforeRequest', function (RequestInterface $request) use (&$lastRequestStart) {
$this->logger->debug('sending dav ' . $request->getMethod() . ' request to external storage: ' . $request->getAbsoluteUrl(), ['app' => 'dav']);
Expand Down
4 changes: 2 additions & 2 deletions lib/private/OCM/Model/OCMProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,11 @@ private function looksValid(): bool {
* apiVersion: '1.0-proposal1',
* endPoint: string,
* publicKey: ISignatory|null,
* resourceTypes: array{
* resourceTypes: list<array{
* name: string,
* shareTypes: list<string>,
* protocols: array<string, string>
* }[],
* }>,
* version: string
* }
*/
Expand Down
8 changes: 8 additions & 0 deletions lib/private/OCM/OCMDiscoveryService.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ public function __construct(
*/
public function discover(string $remote, bool $skipCache = false): IOCMProvider {
$remote = rtrim($remote, '/');
if (!str_starts_with($remote, 'http')) {
// if scheme not specified, we test both;
try {
return $this->discover('https://' . $remote, $skipCache);
} catch (OCMProviderException) {
return $this->discover('http://' . $remote, $skipCache);
}
}

if (!$skipCache) {
try {
Expand Down
20 changes: 10 additions & 10 deletions lib/private/OCM/OCMSignatoryManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@
*/
namespace OC\OCM;

use NCU\Security\PublicPrivateKeyPairs\Exceptions\KeyPairConflictException;
use NCU\Security\PublicPrivateKeyPairs\Exceptions\KeyPairNotFoundException;
use NCU\Security\PublicPrivateKeyPairs\IKeyPairManager;
use NCU\Security\Signature\Exceptions\IdentityNotFoundException;
use NCU\Security\Signature\ISignatoryManager;
use NCU\Security\Signature\ISignatureManager;
use NCU\Security\Signature\Model\IIncomingSignedRequest;
use NCU\Security\Signature\Model\ISignatory;
use NCU\Security\Signature\Model\SignatoryType;
use OC\Security\IdentityProof\Manager;
use OC\Security\Signature\Model\Signatory;
use OCP\IAppConfig;
use OCP\IURLGenerator;
Expand All @@ -40,7 +38,7 @@ public function __construct(
private readonly IAppConfig $appConfig,
private readonly ISignatureManager $signatureManager,
private readonly IURLGenerator $urlGenerator,
private readonly IKeyPairManager $keyPairManager,
private readonly Manager $identityProofManager,
private readonly OCMDiscoveryService $ocmDiscoveryService,
) {
}
Expand Down Expand Up @@ -69,7 +67,6 @@ public function getOptions(): array {
* @inheritDoc
*
* @return ISignatory
* @throws KeyPairConflictException
* @throws IdentityNotFoundException
* @since 31.0.0
*/
Expand All @@ -85,13 +82,16 @@ public function getLocalSignatory(): ISignatory {
$keyId = $this->generateKeyId();
}

try {
$keyPair = $this->keyPairManager->getKeyPair('core', 'ocm_external');
} catch (KeyPairNotFoundException) {
$keyPair = $this->keyPairManager->generateKeyPair('core', 'ocm_external');
if (!$this->identityProofManager->hasAppKey('core', 'ocm_external')) {
$this->identityProofManager->generateAppKey('core', 'ocm_external', [
'algorithm' => 'rsa',
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
]);
}
$keyPair = $this->identityProofManager->getAppKey('core', 'ocm_external');

return new Signatory($keyId, $keyPair->getPublicKey(), $keyPair->getPrivateKey(), local: true);
return new Signatory($keyId, $keyPair->getPublic(), $keyPair->getPrivate(), local: true);
}

/**
Expand Down
Loading

0 comments on commit 5912b44

Please sign in to comment.