55 */
66namespace OCA \CloudFederationAPI \Controller ;
77
8+ use NCU \Federation \ISignedCloudFederationProvider ;
89use NCU \Security \Signature \Exceptions \IdentityNotFoundException ;
910use NCU \Security \Signature \Exceptions \IncomingRequestException ;
1011use NCU \Security \Signature \Exceptions \SignatoryNotFoundException ;
3738use OCP \IURLGenerator ;
3839use OCP \IUserManager ;
3940use OCP \Share \Exceptions \ShareNotFound ;
40- use OCP \Share \IProviderFactory ;
41- use OCP \Share \IShare ;
4241use OCP \Util ;
4342use Psr \Log \LoggerInterface ;
4443
@@ -68,7 +67,6 @@ public function __construct(
6867 private ICloudIdManager $ cloudIdManager ,
6968 private readonly ISignatureManager $ signatureManager ,
7069 private readonly OCMSignatoryManager $ signatoryManager ,
71- private readonly IProviderFactory $ shareProviderFactory ,
7270 ) {
7371 parent ::__construct ($ appName , $ request );
7472 }
@@ -234,16 +232,6 @@ public function addShare($shareWith, $name, $description, $providerId, $owner, $
234232 #[PublicPage]
235233 #[BruteForceProtection(action: 'receiveFederatedShareNotification ' )]
236234 public function receiveNotification ($ notificationType , $ resourceType , $ providerId , ?array $ notification ) {
237- try {
238- // if request is signed and well signed, no exception are thrown
239- // if request is not signed and host is known for not supporting signed request, no exception are thrown
240- $ signedRequest = $ this ->getSignedRequest ();
241- $ this ->confirmShareOrigin ($ signedRequest , $ notification ['sharedSecret ' ] ?? '' );
242- } catch (IncomingRequestException $ e ) {
243- $ this ->logger ->warning ('incoming request exception ' , ['exception ' => $ e ]);
244- return new JSONResponse (['message ' => $ e ->getMessage (), 'validationErrors ' => []], Http::STATUS_BAD_REQUEST );
245- }
246-
247235 // check if all required parameters are set
248236 if ($ notificationType === null ||
249237 $ resourceType === null ||
@@ -259,6 +247,16 @@ public function receiveNotification($notificationType, $resourceType, $providerI
259247 );
260248 }
261249
250+ try {
251+ // if request is signed and well signed, no exception are thrown
252+ // if request is not signed and host is known for not supporting signed request, no exception are thrown
253+ $ signedRequest = $ this ->getSignedRequest ();
254+ $ this ->confirmNotificationIdentity ($ signedRequest , $ resourceType , $ notification );
255+ } catch (IncomingRequestException $ e ) {
256+ $ this ->logger ->warning ('incoming request exception ' , ['exception ' => $ e ]);
257+ return new JSONResponse (['message ' => $ e ->getMessage (), 'validationErrors ' => []], Http::STATUS_BAD_REQUEST );
258+ }
259+
262260 try {
263261 $ provider = $ this ->cloudFederationProviderManager ->getCloudFederationProvider ($ resourceType );
264262 $ result = $ provider ->notificationReceived ($ notificationType , $ providerId , $ notification );
@@ -387,50 +385,53 @@ private function confirmSignedOrigin(?IIncomingSignedRequest $signedRequest, str
387385 }
388386 }
389387
390-
391388 /**
392- * confirm that the value related to share token is in format userid@hostname
393- * and compare hostname with the origin of the signed request.
389+ * confirm identity of the remote instance on notification, based on the share token.
394390 *
395391 * If request is not signed, we still verify that the hostname from the extracted value does,
396392 * actually, not support signed request
397393 *
398394 * @param IIncomingSignedRequest|null $signedRequest
399- * @param string $token
395+ * @param string $resourceType
396+ * @param string $sharedSecret
400397 *
401398 * @throws IncomingRequestException
399+ * @throws BadRequestException
402400 */
403- private function confirmShareOrigin (?IIncomingSignedRequest $ signedRequest , string $ token ): void {
404- if ($ token === '' ) {
401+ private function confirmNotificationIdentity (
402+ ?IIncomingSignedRequest $ signedRequest ,
403+ string $ resourceType ,
404+ array $ notification ,
405+ ): void {
406+ $ sharedSecret = $ notification ['sharedSecret ' ] ?? '' ;
407+ if ($ sharedSecret === '' ) {
405408 throw new BadRequestException (['sharedSecret ' ]);
406409 }
407410
408- $ provider = $ this ->shareProviderFactory ->getProviderForType (IShare::TYPE_REMOTE );
409- $ share = $ provider ->getShareByToken ($ token );
410411 try {
411- $ this ->confirmShareEntry ($ signedRequest , $ share ->getSharedWith ());
412- } catch (IncomingRequestException $ e ) {
413- // notification might come from the instance that owns the share
414- $ this ->logger ->debug ('could not confirm origin on sharedWith ( ' . $ share ->getSharedWIth () . '); going with shareOwner ( ' . $ share ->getShareOwner () . ') ' , ['exception ' => $ e ]);
415- try {
416- $ this ->confirmShareEntry ($ signedRequest , $ share ->getShareOwner ());
417- } catch (IncomingRequestException $ f ) {
418- // if both entry are failing, we log first exception as warning and second exception
419- // will be logged as warning by the controller
420- $ this ->logger ->warning ('could not confirm origin on sharedWith ( ' . $ share ->getSharedWIth () . '); going with shareOwner ( ' . $ share ->getShareOwner () . ') ' , ['exception ' => $ e ]);
421- throw $ f ;
412+ $ provider = $ this ->cloudFederationProviderManager ->getCloudFederationProvider ($ resourceType );
413+ if ($ provider instanceof ISignedCloudFederationProvider) {
414+ $ identity = $ provider ->getFederationIdFromSharedSecret ($ sharedSecret , $ notification );
415+ } else {
416+ $ this ->logger ->debug ('cloud federation provider {provider} does not implements ISignedCloudFederationProvider ' , ['provider ' => $ provider ::class]);
417+ return ;
422418 }
419+ } catch (\Exception $ e ) {
420+ throw new IncomingRequestException ($ e ->getMessage ());
423421 }
422+
423+ $ this ->confirmNotificationEntry ($ signedRequest , $ identity );
424424 }
425425
426+
426427 /**
427428 * @param IIncomingSignedRequest|null $signedRequest
428429 * @param string $entry
429430 *
430431 * @return void
431432 * @throws IncomingRequestException
432433 */
433- private function confirmShareEntry (?IIncomingSignedRequest $ signedRequest , string $ entry ): void {
434+ private function confirmNotificationEntry (?IIncomingSignedRequest $ signedRequest , string $ entry ): void {
434435 $ instance = $ this ->getHostFromFederationId ($ entry );
435436 if ($ signedRequest === null ) {
436437 try {
@@ -440,7 +441,7 @@ private function confirmShareEntry(?IIncomingSignedRequest $signedRequest, strin
440441 return ;
441442 }
442443 } elseif ($ instance !== $ signedRequest ->getOrigin ()) {
443- throw new IncomingRequestException ('token sharedWith ( ' . $ instance . ') not linked to origin ( ' . $ signedRequest ->getOrigin () . ' ) ' );
444+ throw new IncomingRequestException ('remote instance ' . $ instance . ' not linked to origin ' . $ signedRequest ->getOrigin ());
444445 }
445446 }
446447
0 commit comments