]> source.dussan.org Git - nextcloud-server.git/commitdiff
fix(ocm): switching to IdentityProof
authorMaxence Lange <maxence@artificial-owl.com>
Mon, 18 Nov 2024 00:43:47 +0000 (23:43 -0100)
committerMaxence Lange <maxence@artificial-owl.com>
Thu, 21 Nov 2024 10:26:28 +0000 (09:26 -0100)
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
24 files changed:
apps/cloud_federation_api/lib/Capabilities.php
apps/cloud_federation_api/lib/Controller/RequestHandlerController.php
apps/federatedfilesharing/lib/FederatedShareProvider.php
apps/federatedfilesharing/lib/Notifications.php
build/integration/features/bootstrap/FederationContext.php
build/integration/federation_features/cleanup-remote-storage.feature
lib/composer/composer/autoload_classmap.php
lib/composer/composer/autoload_static.php
lib/private/Federation/CloudFederationProviderManager.php
lib/private/Files/Storage/DAV.php
lib/private/OCM/Model/OCMProvider.php
lib/private/OCM/OCMDiscoveryService.php
lib/private/OCM/OCMSignatoryManager.php
lib/private/Security/IdentityProof/Manager.php
lib/private/Security/PublicPrivateKeyPairs/KeyPairManager.php [deleted file]
lib/private/Security/PublicPrivateKeyPairs/Model/KeyPair.php [deleted file]
lib/private/Security/Signature/SignatureManager.php
lib/private/Server.php
lib/public/OCM/IOCMProvider.php
lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairConflictException.php [deleted file]
lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairException.php [deleted file]
lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairNotFoundException.php [deleted file]
lib/unstable/Security/PublicPrivateKeyPairs/IKeyPairManager.php [deleted file]
lib/unstable/Security/PublicPrivateKeyPairs/Model/IKeyPair.php [deleted file]

index 1910a03233791ff12679982b4c75b3e7b4eab741..08806caa5e3e371f8594bfe549b13d7d7b66af6f 100644 (file)
@@ -8,7 +8,7 @@ declare(strict_types=1);
  */
 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;
@@ -79,7 +79,7 @@ class Capabilities implements ICapability {
                        } 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]);
                }
 
index db7f81d55967520f0a0a38ba2aa6ea2206cded41..b1ab1be3f8849d8fd0384a4f3636ed74a53f79e3 100644 (file)
@@ -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;
@@ -14,6 +15,7 @@ use NCU\Security\Signature\Model\IIncomingSignedRequest;
 use OC\OCM\OCMSignatoryManager;
 use OCA\CloudFederationAPI\Config;
 use OCA\CloudFederationAPI\ResponseDefinitions;
+use OCA\FederatedFileSharing\AddressHandler;
 use OCP\AppFramework\Controller;
 use OCP\AppFramework\Http;
 use OCP\AppFramework\Http\Attribute\BruteForceProtection;
@@ -60,6 +62,7 @@ class RequestHandlerController extends Controller {
                private IURLGenerator $urlGenerator,
                private ICloudFederationProviderManager $cloudFederationProviderManager,
                private Config $config,
+               private readonly AddressHandler $addressHandler,
                private readonly IAppConfig $appConfig,
                private ICloudFederationFactory $factory,
                private ICloudIdManager $cloudIdManager,
@@ -289,6 +292,7 @@ class RequestHandlerController extends Controller {
                        $response->throttle();
                        return $response;
                } catch (\Exception $e) {
+                       $this->logger->warning('incoming notification exception', ['exception' => $e]);
                        return new JSONResponse(
                                [
                                        'message' => 'Internal error at ' . $this->urlGenerator->getBaseUrl(),
@@ -376,7 +380,7 @@ class RequestHandlerController extends Controller {
                $body = json_decode($signedRequest->getBody(), true) ?? [];
                $entry = trim($body[$key] ?? '', '@');
                if ($this->getHostFromFederationId($entry) !== $signedRequest->getOrigin()) {
-                       throw new IncomingRequestException('share initiation from different instance');
+                       throw new IncomingRequestException('share initiation (' . $signedRequest->getOrigin() . ') from different instance (' . $entry . ') [key=' . $key . ']');
                }
        }
 
@@ -391,7 +395,6 @@ class RequestHandlerController extends Controller {
         * @param IIncomingSignedRequest|null $signedRequest
         * @param string $token
         *
-        * @return void
         * @throws IncomingRequestException
         */
        private function confirmShareOrigin(?IIncomingSignedRequest $signedRequest, string $token): void {
@@ -401,8 +404,23 @@ class RequestHandlerController extends Controller {
 
                $provider = $this->shareProviderFactory->getProviderForType(IShare::TYPE_REMOTE);
                $share = $provider->getShareByToken($token);
-               $entry = $share->getSharedWith();
+               try {
+                       $this->confirmShareEntry($signedRequest, $share->getSharedWith());
+               } catch (IncomingRequestException) {
+                       // notification might come from the instance that owns the share
+                       $this->logger->debug('could not confirm origin on sharedWith (' . $share->getSharedWIth() . '); going with shareOwner (' . $share->getShareOwner() . ')');
+                       $this->confirmShareEntry($signedRequest, $share->getShareOwner());
+               }
+       }
 
+       /**
+        * @param IIncomingSignedRequest|null $signedRequest
+        * @param string $entry
+        *
+        * @return void
+        * @throws IncomingRequestException
+        */
+       private function confirmShareEntry(?IIncomingSignedRequest $signedRequest, string $entry): void {
                $instance = $this->getHostFromFederationId($entry);
                if ($signedRequest === null) {
                        try {
@@ -412,7 +430,7 @@ class RequestHandlerController extends Controller {
                                return;
                        }
                } elseif ($instance !== $signedRequest->getOrigin()) {
-                       throw new IncomingRequestException('token sharedWith from different instance');
+                       throw new IncomingRequestException('token sharedWith (' . $instance . ') not linked to origin (' . $signedRequest->getOrigin() . ')');
                }
        }
 
@@ -423,20 +441,16 @@ class RequestHandlerController extends Controller {
         */
        private function getHostFromFederationId(string $entry): string {
                if (!str_contains($entry, '@')) {
-                       throw new IncomingRequestException('entry does not contains @');
+                       throw new IncomingRequestException('entry ' . $entry . ' does not contains @');
                }
-               [, $rightPart] = explode('@', $entry, 2);
+               $rightPart = substr($entry, strrpos($entry, '@') + 1);
 
-               $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;
+               // in case the full scheme is sent; getting rid of it
+               $rightPart = $this->addressHandler->removeProtocolFromUrl($rightPart);
+               try {
+                       return $this->signatureManager->extractIdentityFromUri('https://' . $rightPart);
+               } catch (IdentityNotFoundException) {
+                       throw new IncomingRequestException('invalid host within federation id: ' . $entry);
                }
-
-               throw new IncomingRequestException('host is empty');
        }
 }
index 11e78f5cb97f6d5535e188890f35d8d854ef8e6d..139c873b0d6e45253c0f98735386843fd5000311 100644 (file)
@@ -250,7 +250,8 @@ class FederatedShareProvider implements IShareProvider {
                        $remote,
                        $shareWith,
                        $share->getPermissions(),
-                       $share->getNode()->getName()
+                       $share->getNode()->getName(),
+                       $share->getShareType(),
                );
 
                return [$token, $remoteId];
index 3c97177358788ab114e13b398898604c40110795..3a111ae0ed0e3313449b417dcb4c60ad2975f953 100644 (file)
@@ -108,12 +108,13 @@ class Notifications {
         * @throws HintException
         * @throws \OC\ServerNotAvailableException
         */
-       public function requestReShare($token, $id, $shareId, $remote, $shareWith, $permission, $filename) {
+       public function requestReShare($token, $id, $shareId, $remote, $shareWith, $permission, $filename, $shareType) {
                $fields = [
                        'shareWith' => $shareWith,
                        'token' => $token,
                        'permission' => $permission,
                        'remoteId' => $shareId,
+                       'shareType' => $shareType,
                ];
 
                $ocmFields = $fields;
index e146b46644cda43a7ffa01a27b2a438819c559ea..bbd81396df56a6f0995c2dd8b269f6dae95f16e7 100644 (file)
@@ -38,7 +38,7 @@ class FederationContext implements Context, SnippetAcceptingContext {
 
                $port = getenv('PORT_FED');
 
-               self::$phpFederatedServerPid = exec('php -S localhost:' . $port . ' -t ../../ >/dev/null & echo $!');
+               self::$phpFederatedServerPid = exec('PHP_CLI_SERVER_WORKERS=2 php -S localhost:' . $port . ' -t ../../ >/dev/null & echo $!');
        }
 
        /**
index a017b59bcf4cfdde74f25c6500a3881d449f833b..a3585bdee96c23f71e503e8de1daf72b8b3203f3 100644 (file)
@@ -4,6 +4,27 @@ Feature: cleanup-remote-storage
   Background:
     Given using api version "1"
 
+  Scenario: cleanup remote storage with no storage
+    Given Using server "LOCAL"
+    And user "user0" exists
+    Given Using server "REMOTE"
+    And user "user1" exists
+    # Rename file so it has a unique name in the target server (as the target
+    # 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 Deleting last share
+    And the OCS status code should be "100"
+    And the HTTP status code should be "200"
+    And Deleting last share
+    And Using server "LOCAL"
+    When invoking occ with "sharing:cleanup-remote-storage"
+    Then the command was successful
+    And the command output contains the text "0 remote storage(s) need(s) to be checked"
+    And the command output contains the text "0 remote share(s) exist"
+    And the command output contains the text "no storages deleted"
+
   Scenario: cleanup remote storage with active storages
     Given Using server "LOCAL"
     And user "user0" exists
@@ -35,9 +56,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
index b04f938d2366afa831154e5deac492539ac0b29e..744f3b8b8c51ad94f085e2837f6efe9ac251e2ff 100644 (file)
@@ -1901,8 +1901,6 @@ return array(
     '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',
index dea35ecdfcd114bfaa4d7196a0c50614c602c9db..70f9b3b3e6328a066ca5f5fea646935a8b0fcc0c 100644 (file)
@@ -1942,8 +1942,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',
index eeb161c3b2514e6f73d30ce3db7337208b4a0740..74935ead40144ed6a066819cfa1d6eeb9a741cd1 100644 (file)
@@ -18,6 +18,7 @@ use OCP\Federation\ICloudFederationProvider;
 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;
@@ -105,25 +106,11 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
        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 : [];
@@ -149,22 +136,9 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
         */
        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 {
@@ -183,26 +157,11 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
         */
        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 : [];
@@ -222,21 +181,9 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
         * @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 {
@@ -256,6 +203,40 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
                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'],
index 597b3f474888894c6b9a15730d9bbcdc714282bc..10670d6331a0efefe44c7006bb5fa0f097e10702 100644 (file)
@@ -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;
@@ -104,7 +103,6 @@ class DAV extends Common {
                        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');
@@ -164,11 +162,6 @@ class DAV extends Common {
                        }
                }
 
-               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']);
index cd4e9c49c3b29943628a5b4e6e5ce17649c4bed5..95ba83882f22bc242512c1cf9948a8d43dc4d666 100644 (file)
@@ -210,11 +210,11 @@ class OCMProvider implements IOCMProvider {
         *      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
         *  }
         */
index f39d0e2382177378f6a2f2899f3c512edf9c2922..30e7909a6aae0840a97c0d2cbef14f7d64d613e1 100644 (file)
@@ -46,6 +46,14 @@ class OCMDiscoveryService implements IOCMDiscoveryService {
         */
        public function discover(string $remote, bool $skipCache = false): IOCMProvider {
                $remote = rtrim($remote, '/');
+               if (!str_starts_with($remote, 'http://') && !str_starts_with($remote, 'https://')) {
+                       // 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 {
@@ -65,10 +73,7 @@ class OCMDiscoveryService implements IOCMDiscoveryService {
                        if ($this->config->getSystemValueBool('sharing.federation.allowSelfSignedCertificates') === true) {
                                $options['verify'] = false;
                        }
-                       $response = $client->get(
-                               $remote . '/ocm-provider/',
-                               $options,
-                       );
+                       $response = $client->get($remote . '/ocm-provider/', $options);
 
                        if ($response->getStatusCode() === Http::STATUS_OK) {
                                $body = $response->getBody();
index 1508c1db1ef1b09b54df3eaf6791a6ef0e52d8d6..a90bb2c1f395ea725c7591533e1c6c25305e98ea 100644 (file)
@@ -8,15 +8,13 @@ declare(strict_types=1);
  */
 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;
@@ -40,7 +38,7 @@ class OCMSignatoryManager implements ISignatoryManager {
                private readonly IAppConfig $appConfig,
                private readonly ISignatureManager $signatureManager,
                private readonly IURLGenerator $urlGenerator,
-               private readonly IKeyPairManager $keyPairManager,
+               private readonly Manager $identityProofManager,
                private readonly OCMDiscoveryService $ocmDiscoveryService,
        ) {
        }
@@ -69,7 +67,6 @@ class OCMSignatoryManager implements ISignatoryManager {
         * @inheritDoc
         *
         * @return ISignatory
-        * @throws KeyPairConflictException
         * @throws IdentityNotFoundException
         * @since 31.0.0
         */
@@ -85,13 +82,16 @@ class OCMSignatoryManager implements ISignatoryManager {
                        $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);
        }
 
        /**
index 0ce760ccc63b3ac9658e25b8c0efb677818f185a..de0b3fe6bd16e401d244d94aafecda87778400b1 100644 (file)
@@ -10,6 +10,7 @@ namespace OC\Security\IdentityProof;
 
 use OC\Files\AppData\Factory;
 use OCP\Files\IAppData;
+use OCP\Files\NotFoundException;
 use OCP\IConfig;
 use OCP\IUser;
 use OCP\Security\ICrypto;
@@ -31,18 +32,20 @@ class Manager {
         * Calls the openssl functions to generate a public and private key.
         * In a separate function for unit testing purposes.
         *
+        * @param array $options config options to generate key {@see openssl_csr_new}
+        *
         * @return array [$publicKey, $privateKey]
         * @throws \RuntimeException
         */
-       protected function generateKeyPair(): array {
+       protected function generateKeyPair(array $options = []): array {
                $config = [
-                       'digest_alg' => 'sha512',
-                       'private_key_bits' => 2048,
+                       'digest_alg' => $options['algorithm'] ?? 'sha512',
+                       'private_key_bits' => $options['bits'] ?? 2048,
+                       'private_key_type' => $options['type'] ?? OPENSSL_KEYTYPE_RSA,
                ];
 
                // Generate new key
                $res = openssl_pkey_new($config);
-
                if ($res === false) {
                        $this->logOpensslError();
                        throw new \RuntimeException('OpenSSL reported a problem');
@@ -65,15 +68,17 @@ class Manager {
         * Note: If a key already exists it will be overwritten
         *
         * @param string $id key id
+        * @param array $options config options to generate key {@see openssl_csr_new}
+        *
         * @throws \RuntimeException
         */
-       protected function generateKey(string $id): Key {
-               [$publicKey, $privateKey] = $this->generateKeyPair();
+       protected function generateKey(string $id, array $options = []): Key {
+               [$publicKey, $privateKey] = $this->generateKeyPair($options);
 
                // Write the private and public key to the disk
                try {
                        $this->appData->newFolder($id);
-               } catch (\Exception $e) {
+               } catch (\Exception) {
                }
                $folder = $this->appData->getFolder($id);
                $folder->newFile('private')
@@ -125,6 +130,38 @@ class Manager {
                return $this->retrieveKey('system-' . $instanceId);
        }
 
+       public function hasAppKey(string $app, string $name): bool {
+               $id = $this->generateAppKeyId($app, $name);
+               try {
+                       $this->appData->getFolder($id);
+                       return true;
+               } catch (NotFoundException) {
+                       return false;
+               }
+       }
+
+       public function getAppKey(string $app, string $name): Key {
+               return $this->retrieveKey($this->generateAppKeyId($app, $name));
+       }
+
+       public function generateAppKey(string $app, string $name, array $options = []): Key {
+               return $this->generateKey($this->generateAppKeyId($app, $name), $options);
+       }
+
+       public function deleteAppKey(string $app, string $name): bool {
+               try {
+                       $folder = $this->appData->getFolder($this->generateAppKeyId($app, $name));
+               } catch (NotFoundException) {
+                       return false;
+               }
+               $folder->delete();
+               return true;
+       }
+
+       private function generateAppKeyId(string $app, string $name): string {
+               return 'app-' . $app . '-' . $name;
+       }
+
        private function logOpensslError(): void {
                $errors = [];
                while ($error = openssl_error_string()) {
diff --git a/lib/private/Security/PublicPrivateKeyPairs/KeyPairManager.php b/lib/private/Security/PublicPrivateKeyPairs/KeyPairManager.php
deleted file mode 100644 (file)
index 0af960b..0000000
+++ /dev/null
@@ -1,182 +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\PublicPrivateKeyPairs;
-
-use NCU\Security\PublicPrivateKeyPairs\Exceptions\KeyPairConflictException;
-use NCU\Security\PublicPrivateKeyPairs\Exceptions\KeyPairNotFoundException;
-use NCU\Security\PublicPrivateKeyPairs\IKeyPairManager;
-use NCU\Security\PublicPrivateKeyPairs\Model\IKeyPair;
-use OC\Security\PublicPrivateKeyPairs\Model\KeyPair;
-use OCP\IAppConfig;
-
-/**
- * @inheritDoc
- *
- * KeyPairManager store internal public/private key pair using AppConfig, taking advantage of the encryption
- * and lazy loading.
- *
- * @since 31.0.0
- */
-class KeyPairManager implements IKeyPairManager {
-       private const CONFIG_PREFIX = 'security.keypair.';
-
-       public function __construct(
-               private readonly IAppConfig $appConfig,
-       ) {
-       }
-
-       /**
-        * @inheritDoc
-        *
-        * @param string $app appId
-        * @param string $name key name
-        * @param array $options algorithms, metadata
-        *
-        * @return IKeyPair
-        * @throws KeyPairConflictException if a key already exist
-        * @since 31.0.0
-        */
-       public function generateKeyPair(string $app, string $name, array $options = []): IKeyPair {
-               if ($this->hasKeyPair($app, $name)) {
-                       throw new KeyPairConflictException('key pair already exist');
-               }
-
-               $keyPair = new KeyPair($app, $name);
-
-               [$publicKey, $privateKey] = $this->generateKeys($options);
-               $keyPair->setPublicKey($publicKey)
-                       ->setPrivateKey($privateKey)
-                       ->setOptions($options);
-
-               $this->appConfig->setValueArray(
-                       $app, $this->generateAppConfigKey($name),
-                       [
-                               'public' => $keyPair->getPublicKey(),
-                               'private' => $keyPair->getPrivateKey(),
-                               'options' => $keyPair->getOptions()
-                       ],
-                       lazy:      true,
-                       sensitive: true
-               );
-
-               return $keyPair;
-       }
-
-       /**
-        * @inheritDoc
-        *
-        * @param string $app appId
-        * @param string $name key name
-        *
-        * @return bool TRUE if key pair exists in database
-        * @since 31.0.0
-        */
-       public function hasKeyPair(string $app, string $name): bool {
-               $key = $this->generateAppConfigKey($name);
-               return $this->appConfig->hasKey($app, $key, lazy: true);
-       }
-
-       /**
-        * @inheritDoc
-        *
-        * @param string $app appId
-        * @param string $name key name
-        *
-        * @return IKeyPair
-        * @throws KeyPairNotFoundException if key pair is not known
-        * @since 31.0.0
-        */
-       public function getKeyPair(string $app, string $name): IKeyPair {
-               if (!$this->hasKeyPair($app, $name)) {
-                       throw new KeyPairNotFoundException('unknown key pair');
-               }
-
-               $key = $this->generateAppConfigKey($name);
-               $stored = $this->appConfig->getValueArray($app, $key, lazy: true);
-               if (!array_key_exists('public', $stored) ||
-                       !array_key_exists('private', $stored)) {
-                       throw new KeyPairNotFoundException('corrupted key pair');
-               }
-
-               $keyPair = new KeyPair($app, $name);
-               return $keyPair->setPublicKey($stored['public'])
-                       ->setPrivateKey($stored['private'])
-                       ->setOptions($stored['options'] ?? []);
-       }
-
-       /**
-        * @inheritDoc
-        *
-        * @param string $app appid
-        * @param string $name key name
-        *
-        * @since 31.0.0
-        */
-       public function deleteKeyPair(string $app, string $name): void {
-               $this->appConfig->deleteKey('core', $this->generateAppConfigKey($name));
-       }
-
-       /**
-        * @inheritDoc
-        *
-        * @param IKeyPair $keyPair keypair to test
-        *
-        * @return bool
-        * @since 31.0.0
-        */
-       public function testKeyPair(IKeyPair $keyPair): bool {
-               $clear = md5((string)time());
-
-               // signing with private key
-               openssl_sign($clear, $signed, $keyPair->getPrivateKey(), OPENSSL_ALGO_SHA256);
-               $encoded = base64_encode($signed);
-
-               // verify with public key
-               $signed = base64_decode($encoded);
-               return (openssl_verify($clear, $signed, $keyPair->getPublicKey(), 'sha256') === 1);
-       }
-
-       /**
-        * return appconfig key based on name of the key pair
-        *
-        * @param string $name
-        *
-        * @return string
-        */
-       private function generateAppConfigKey(string $name): string {
-               return self::CONFIG_PREFIX . $name;
-       }
-
-       /**
-        * generate the key pair, based on $options with the following default values:
-        *   [
-        *     'algorithm' => 'rsa',
-        *     'bits' => 2048,
-        *     'type' => OPENSSL_KEYTYPE_RSA
-        *   ]
-        *
-        * @param array $options
-        *
-        * @return array
-        */
-       private function generateKeys(array $options = []): array {
-               $res = openssl_pkey_new(
-                       [
-                               'digest_alg' => $options['algorithm'] ?? 'rsa',
-                               'private_key_bits' => $options['bits'] ?? 2048,
-                               'private_key_type' => $options['type'] ?? OPENSSL_KEYTYPE_RSA,
-                       ]
-               );
-
-               openssl_pkey_export($res, $privateKey);
-               $publicKey = openssl_pkey_get_details($res)['key'];
-
-               return [$publicKey, $privateKey];
-       }
-}
diff --git a/lib/private/Security/PublicPrivateKeyPairs/Model/KeyPair.php b/lib/private/Security/PublicPrivateKeyPairs/Model/KeyPair.php
deleted file mode 100644 (file)
index 523f7c1..0000000
+++ /dev/null
@@ -1,114 +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\PublicPrivateKeyPairs\Model;
-
-use NCU\Security\PublicPrivateKeyPairs\Model\IKeyPair;
-
-/**
- * @inheritDoc
- *
- * @since 31.0.0
- */
-class KeyPair implements IKeyPair {
-       private string $publicKey = '';
-       private string $privateKey = '';
-       private array $options = [];
-
-       public function __construct(
-               private readonly string $app,
-               private readonly string $name,
-       ) {
-       }
-
-       /**
-        * @inheritDoc
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getApp(): string {
-               return $this->app;
-       }
-
-       /**
-        * @inheritDoc
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getName(): string {
-               return $this->name;
-       }
-
-       /**
-        * @inheritDoc
-        *
-        * @param string $publicKey
-        * @return IKeyPair
-        * @since 31.0.0
-        */
-       public function setPublicKey(string $publicKey): IKeyPair {
-               $this->publicKey = $publicKey;
-               return $this;
-       }
-
-       /**
-        * @inheritDoc
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getPublicKey(): string {
-               return $this->publicKey;
-       }
-
-       /**
-        * @inheritDoc
-        *
-        * @param string $privateKey
-        * @return IKeyPair
-        * @since 31.0.0
-        */
-       public function setPrivateKey(string $privateKey): IKeyPair {
-               $this->privateKey = $privateKey;
-               return $this;
-       }
-
-       /**
-        * @inheritDoc
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getPrivateKey(): string {
-               return $this->privateKey;
-       }
-
-       /**
-        * @inheritDoc
-        *
-        * @param array $options
-        * @return IKeyPair
-        * @since 31.0.0
-        */
-       public function setOptions(array $options): IKeyPair {
-               $this->options = $options;
-               return $this;
-       }
-
-       /**
-        * @inheritDoc
-        *
-        * @return array
-        * @since 31.0.0
-        */
-       public function getOptions(): array {
-               return $this->options;
-       }
-}
index d087e8ebdeb0ccf26083bf341c3362162aaa3bbe..8717171f4b4159665c6374efd7d18efda657c495 100644 (file)
@@ -112,9 +112,7 @@ class SignatureManager implements ISignatureManager {
                        $this->prepIncomingSignatureHeader($signedRequest);
                        $this->verifyIncomingSignatureHeader($signedRequest);
                        $this->prepEstimatedSignature($signedRequest, $options['extraSignatureHeaders'] ?? []);
-                       $this->verifyIncomingRequestSignature(
-                               $signedRequest, $signatoryManager, $options['ttlSignatory'] ?? self::SIGNATORY_TTL
-                       );
+                       $this->verifyIncomingRequestSignature($signedRequest, $signatoryManager, $options['ttlSignatory'] ?? self::SIGNATORY_TTL);
                } catch (SignatureException $e) {
                        $this->logger->warning(
                                'signature could not be verified', [
@@ -724,7 +722,6 @@ class SignatureManager implements ISignatureManager {
                        case SignatoryType::FORGIVABLE:
                                $this->deleteSignatory($knownSignatory->getKeyId());
                                $this->insertSignatory($signatory);
-
                                return;
 
                        case SignatoryType::REFRESHABLE:
@@ -735,12 +732,10 @@ class SignatureManager implements ISignatureManager {
                        case SignatoryType::TRUSTED:
                                // TODO: send notice to admin
                                throw new SignatoryConflictException();
-                               break;
 
                        case SignatoryType::STATIC:
                                // TODO: send warning to admin
                                throw new SignatoryConflictException();
-                               break;
                }
        }
 
index 7ff0045b03fa8cbeacd3a909513033363410084c..2167bccec8982d27041afad1956d22d1b20fb7ca 100644 (file)
@@ -103,7 +103,6 @@ use OC\Security\CSRF\CsrfTokenManager;
 use OC\Security\CSRF\TokenStorage\SessionStorage;
 use OC\Security\Hasher;
 use OC\Security\Ip\RemoteAddress;
-use OC\Security\PublicPrivateKeyPairs\KeyPairManager;
 use OC\Security\RateLimiting\Limiter;
 use OC\Security\SecureRandom;
 use OC\Security\Signature\SignatureManager;
@@ -1290,7 +1289,6 @@ class Server extends ServerContainer implements IServerContainer {
 
                $this->registerAlias(IRichTextFormatter::class, \OC\RichObjectStrings\RichTextFormatter::class);
 
-               $this->registerAlias(IKeyPairManager::class, KeyPairManager::class);
                $this->registerAlias(ISignatureManager::class, SignatureManager::class);
 
                $this->connectDispatcher();
index 789462efd7828a589c037dd5fbb5505552b8a4f0..dd36a1c6057154d09430633d83f97bf9670f879a 100644 (file)
@@ -154,11 +154,11 @@ interface IOCMProvider extends JsonSerializable {
         *     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
         * }
         * @since 28.0.0
diff --git a/lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairConflictException.php b/lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairConflictException.php
deleted file mode 100644 (file)
index b808342..0000000
+++ /dev/null
@@ -1,18 +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\PublicPrivateKeyPairs\Exceptions;
-
-/**
- * conflict between public and private key pair
- *
- * @experimental 31.0.0
- * @since 31.0.0
- */
-class KeyPairConflictException extends KeyPairException {
-}
diff --git a/lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairException.php b/lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairException.php
deleted file mode 100644 (file)
index 1cbcf13..0000000
+++ /dev/null
@@ -1,20 +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\PublicPrivateKeyPairs\Exceptions;
-
-use Exception;
-
-/**
- * global exception related to key pairs
- *
- * @experimental 31.0.0
- * @since 31.0.0
- */
-class KeyPairException extends Exception {
-}
diff --git a/lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairNotFoundException.php b/lib/unstable/Security/PublicPrivateKeyPairs/Exceptions/KeyPairNotFoundException.php
deleted file mode 100644 (file)
index 138fd88..0000000
+++ /dev/null
@@ -1,16 +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\PublicPrivateKeyPairs\Exceptions;
-
-/**
- * @experimental 31.0.0
- * @since 31.0.0
- */
-class KeyPairNotFoundException extends KeyPairException {
-}
diff --git a/lib/unstable/Security/PublicPrivateKeyPairs/IKeyPairManager.php b/lib/unstable/Security/PublicPrivateKeyPairs/IKeyPairManager.php
deleted file mode 100644 (file)
index a993cec..0000000
+++ /dev/null
@@ -1,80 +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\PublicPrivateKeyPairs;
-
-use NCU\Security\PublicPrivateKeyPairs\Exceptions\KeyPairConflictException;
-use NCU\Security\PublicPrivateKeyPairs\Exceptions\KeyPairNotFoundException;
-use NCU\Security\PublicPrivateKeyPairs\Model\IKeyPair;
-
-/**
- * IKeyPairManager contains a group of method to create/manage/store internal public/private key pair.
- *
- * @experimental 31.0.0
- * @since 31.0.0
- */
-interface IKeyPairManager {
-
-       /**
-        * generate and store public/private key pair.
-        * throws exception if key pair already exist
-        *
-        * @param string $app appId
-        * @param string $name key name
-        * @param array $options algorithms, metadata
-        *
-        * @return IKeyPair
-        * @throws KeyPairConflictException if a key already exist
-        * @since 31.0.0
-        */
-       public function generateKeyPair(string $app, string $name, array $options = []): IKeyPair;
-
-       /**
-        * returns if key pair is known.
-        *
-        * @param string $app appId
-        * @param string $name key name
-        *
-        * @return bool TRUE if key pair exists in database
-        * @since 31.0.0
-        */
-       public function hasKeyPair(string $app, string $name): bool;
-
-       /**
-        * return key pair from database based on $app and $name.
-        * throws exception if key pair does not exist
-        *
-        * @param string $app appId
-        * @param string $name key name
-        *
-        * @return IKeyPair
-        * @throws KeyPairNotFoundException if key pair is not known
-        * @since 31.0.0
-        */
-       public function getKeyPair(string $app, string $name): IKeyPair;
-
-       /**
-        * delete key pair from database
-        *
-        * @param string $app appid
-        * @param string $name key name
-        *
-        * @since 31.0.0
-        */
-       public function deleteKeyPair(string $app, string $name): void;
-
-       /**
-        * test key pair by encrypting/decrypting a string
-        *
-        * @param IKeyPair $keyPair keypair to test
-        *
-        * @return bool
-        * @since 31.0.0
-        */
-       public function testKeyPair(IKeyPair $keyPair): bool;
-}
diff --git a/lib/unstable/Security/PublicPrivateKeyPairs/Model/IKeyPair.php b/lib/unstable/Security/PublicPrivateKeyPairs/Model/IKeyPair.php
deleted file mode 100644 (file)
index 92585b9..0000000
+++ /dev/null
@@ -1,85 +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\PublicPrivateKeyPairs\Model;
-
-/**
- * simple model that store key pair, its name, its origin (app)
- * and the options used during its creation
- *
- * @experimental 31.0.0
- * @since 31.0.0
- */
-interface IKeyPair {
-       /**
-        * returns id of the app owning the key pair
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getApp(): string;
-
-       /**
-        * returns name of the key pair
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getName(): string;
-
-       /**
-        * set public key
-        *
-        * @param string $publicKey
-        * @return IKeyPair
-        * @since 31.0.0
-        */
-       public function setPublicKey(string $publicKey): IKeyPair;
-
-       /**
-        * returns public key
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getPublicKey(): string;
-
-       /**
-        * set private key
-        *
-        * @param string $privateKey
-        * @return IKeyPair
-        * @since 31.0.0
-        */
-       public function setPrivateKey(string $privateKey): IKeyPair;
-
-       /**
-        * returns private key
-        *
-        * @return string
-        * @since 31.0.0
-        */
-       public function getPrivateKey(): string;
-
-       /**
-        * set options
-        *
-        * @param array $options
-        * @return IKeyPair
-        * @since 31.0.0
-        */
-       public function setOptions(array $options): IKeyPair;
-
-       /**
-        * returns options
-        *
-        * @return array
-        * @since 31.0.0
-        */
-       public function getOptions(): array;
-}