diff options
Diffstat (limited to 'lib/unstable/Security/Signature/ISignatureManager.php')
-rw-r--r-- | lib/unstable/Security/Signature/ISignatureManager.php | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/lib/unstable/Security/Signature/ISignatureManager.php b/lib/unstable/Security/Signature/ISignatureManager.php new file mode 100644 index 00000000000..655454f67e7 --- /dev/null +++ b/lib/unstable/Security/Signature/ISignatureManager.php @@ -0,0 +1,136 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace NCU\Security\Signature; + +use NCU\Security\Signature\Exceptions\IdentityNotFoundException; +use NCU\Security\Signature\Exceptions\IncomingRequestException; +use NCU\Security\Signature\Exceptions\SignatoryNotFoundException; +use NCU\Security\Signature\Exceptions\SignatureException; +use NCU\Security\Signature\Exceptions\SignatureNotFoundException; +use NCU\Security\Signature\Model\Signatory; + +/** + * ISignatureManager is a service integrated to core that provide tools + * to set/get authenticity of/from outgoing/incoming request. + * + * Quick description of the signature, added to the headers + * { + * "(request-target)": "post /path", + * "content-length": 385, + * "date": "Mon, 08 Jul 2024 14:16:20 GMT", + * "digest": "SHA-256=U7gNVUQiixe5BRbp4Tg0xCZMTcSWXXUZI2\\/xtHM40S0=", + * "host": "hostname.of.the.recipient", + * "Signature": "keyId=\"https://author.hostname/key\",algorithm=\"sha256\",headers=\"content-length date digest host\",signature=\"DzN12OCS1rsA[...]o0VmxjQooRo6HHabg==\"" + * } + * + * 'content-length' is the total length of the data/content + * 'date' is the datetime the request have been initiated + * 'digest' is a checksum of the data/content + * 'host' is the hostname of the recipient of the request (remote when signing outgoing request, local on incoming request) + * 'Signature' contains the signature generated using the private key, and metadata: + * - 'keyId' is a unique id, formatted as an url. hostname is used to retrieve the public key via custom discovery + * - 'algorithm' define the algorithm used to generate signature + * - 'headers' contains a list of element used during the generation of the signature + * - 'signature' is the encrypted string, using local private key, of an array containing elements + * listed in 'headers' and their value. Some elements (content-length date digest host) are mandatory + * to ensure authenticity override protection. + * + * This interface can be used to inject {@see SignatureManager} in your code: + * + * ```php + * public function __construct( + * private ISignatureManager $signatureManager, + * ) {} + * ``` + * + * instead obtained from {@see ISignatureManager::getIncomingSignedRequest}. + * + * @experimental 31.0.0 + */ +interface ISignatureManager { + /** + * Extracting data from headers and body from the incoming request. + * Compare headers and body to confirm authenticity of remote instance. + * Returns details about the signed request or throws exception. + * + * Should be called from Controller. + * + * @param ISignatoryManager $signatoryManager used to get details about remote instance + * @param string|null $body if NULL, body will be extracted from php://input + * + * @return IIncomingSignedRequest + * @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 + * @experimental 31.0.0 + */ + public function getIncomingSignedRequest(ISignatoryManager $signatoryManager, ?string $body = null): IIncomingSignedRequest; + + /** + * Preparing signature (and headers) to sign an outgoing request. + * Returns a IOutgoingSignedRequest containing all details to finalise the packaging of the whole payload + * + * @param ISignatoryManager $signatoryManager + * @param string $content body to be signed + * @param string $method needed in the signature + * @param string $uri needed in the signature + * + * @return IOutgoingSignedRequest + * @experimental 31.0.0 + */ + public function getOutgoingSignedRequest(ISignatoryManager $signatoryManager, string $content, string $method, string $uri): IOutgoingSignedRequest; + + /** + * Complete the full process of signing and filling headers from payload when generating + * an outgoing request with IClient + * + * @param ISignatoryManager $signatoryManager + * @param array $payload original payload, will be used to sign and completed with new headers with signature elements + * @param string $method needed in the signature + * @param string $uri needed in the signature + * + * @return array new payload to be sent, including original payload and signature elements in headers + * @experimental 31.0.0 + */ + public function signOutgoingRequestIClientPayload(ISignatoryManager $signatoryManager, array $payload, string $method, string $uri): array; + + /** + * returns remote signatory stored in local database, based on the remote host. + * + * @param string $host remote host + * @param string $account linked account, should be used when multiple signature can exist for the same host + * + * @return Signatory + * @throws SignatoryNotFoundException if entry does not exist in local database + * @experimental 31.0.0 + */ + public function getSignatory(string $host, string $account = ''): Signatory; + + /** + * returns a fully formatted keyId, based on a fix hostname and path + * + * @param string $path + * + * @return string + * @throws IdentityNotFoundException if hostname is not set + * @experimental 31.0.0 + */ + public function generateKeyIdFromConfig(string $path): string; + + /** + * returns hostname:port extracted from an uri + * + * @param string $uri + * + * @return string + * @throws IdentityNotFoundException if identity cannot be extracted + * @experimental 31.0.0 + */ + public function extractIdentityFromUri(string $uri): string; +} |