Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions apps/cloud_federation_api/appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@
<nextcloud min-version="36" max-version="36"/>
</dependencies>

<background-jobs>
<job>OCA\CloudFederationAPI\BackgroundJob\CleanupExpiredOcmTokensJob</job>
</background-jobs>
<repair-steps>
<post-migration>
<step>OCA\CloudFederationAPI\Migration\DropFederatedInvitesTable</step>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,13 @@
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'OCA\\CloudFederationAPI\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
'OCA\\CloudFederationAPI\\BackgroundJob\\CleanupExpiredOcmTokensJob' => $baseDir . '/../lib/BackgroundJob/CleanupExpiredOcmTokensJob.php',
'OCA\\CloudFederationAPI\\Config' => $baseDir . '/../lib/Config.php',
'OCA\\CloudFederationAPI\\Controller\\OCMRequestController' => $baseDir . '/../lib/Controller/OCMRequestController.php',
'OCA\\CloudFederationAPI\\Controller\\RequestHandlerController' => $baseDir . '/../lib/Controller/RequestHandlerController.php',
'OCA\\CloudFederationAPI\\Controller\\TokenController' => $baseDir . '/../lib/Controller/TokenController.php',
'OCA\\CloudFederationAPI\\Db\\OcmTokenMap' => $baseDir . '/../lib/Db/OcmTokenMap.php',
'OCA\\CloudFederationAPI\\Db\\OcmTokenMapMapper' => $baseDir . '/../lib/Db/OcmTokenMapMapper.php',
'OCA\\CloudFederationAPI\\Listener\\ShareDeletedListener' => $baseDir . '/../lib/Listener/ShareDeletedListener.php',
'OCA\\CloudFederationAPI\\Migration\\DropFederatedInvitesTable' => $baseDir . '/../lib/Migration/DropFederatedInvitesTable.php',
'OCA\\CloudFederationAPI\\Migration\\Version1016Date202502262004' => $baseDir . '/../lib/Migration/Version1016Date202502262004.php',
'OCA\\CloudFederationAPI\\Migration\\Version1017Date20260306120000' => $baseDir . '/../lib/Migration/Version1017Date20260306120000.php',
'OCA\\CloudFederationAPI\\Migration\\Version2000Date20260919141251' => $baseDir . '/../lib/Migration/Version2000Date20260919141251.php',
'OCA\\CloudFederationAPI\\ResponseDefinitions' => $baseDir . '/../lib/ResponseDefinitions.php',
'OCA\\CloudFederationAPI\\Service\\OcmTokenService' => $baseDir . '/../lib/Service/OcmTokenService.php',
);
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,15 @@ class ComposerStaticInitCloudFederationAPI
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'OCA\\CloudFederationAPI\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
'OCA\\CloudFederationAPI\\BackgroundJob\\CleanupExpiredOcmTokensJob' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupExpiredOcmTokensJob.php',
'OCA\\CloudFederationAPI\\Config' => __DIR__ . '/..' . '/../lib/Config.php',
'OCA\\CloudFederationAPI\\Controller\\OCMRequestController' => __DIR__ . '/..' . '/../lib/Controller/OCMRequestController.php',
'OCA\\CloudFederationAPI\\Controller\\RequestHandlerController' => __DIR__ . '/..' . '/../lib/Controller/RequestHandlerController.php',
'OCA\\CloudFederationAPI\\Controller\\TokenController' => __DIR__ . '/..' . '/../lib/Controller/TokenController.php',
'OCA\\CloudFederationAPI\\Db\\OcmTokenMap' => __DIR__ . '/..' . '/../lib/Db/OcmTokenMap.php',
'OCA\\CloudFederationAPI\\Db\\OcmTokenMapMapper' => __DIR__ . '/..' . '/../lib/Db/OcmTokenMapMapper.php',
'OCA\\CloudFederationAPI\\Listener\\ShareDeletedListener' => __DIR__ . '/..' . '/../lib/Listener/ShareDeletedListener.php',
'OCA\\CloudFederationAPI\\Migration\\DropFederatedInvitesTable' => __DIR__ . '/..' . '/../lib/Migration/DropFederatedInvitesTable.php',
'OCA\\CloudFederationAPI\\Migration\\Version1016Date202502262004' => __DIR__ . '/..' . '/../lib/Migration/Version1016Date202502262004.php',
'OCA\\CloudFederationAPI\\Migration\\Version1017Date20260306120000' => __DIR__ . '/..' . '/../lib/Migration/Version1017Date20260306120000.php',
'OCA\\CloudFederationAPI\\Migration\\Version2000Date20260919141251' => __DIR__ . '/..' . '/../lib/Migration/Version2000Date20260919141251.php',
'OCA\\CloudFederationAPI\\ResponseDefinitions' => __DIR__ . '/..' . '/../lib/ResponseDefinitions.php',
'OCA\\CloudFederationAPI\\Service\\OcmTokenService' => __DIR__ . '/..' . '/../lib/Service/OcmTokenService.php',
);

public static function getInitializer(ClassLoader $loader)
Expand Down
3 changes: 0 additions & 3 deletions apps/cloud_federation_api/lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@

namespace OCA\CloudFederationAPI\AppInfo;

use OCA\CloudFederationAPI\Listener\ShareDeletedListener;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\Share\Events\ShareDeletedEvent;

class Application extends App implements IBootstrap {
public const APP_ID = 'cloud_federation_api';
Expand All @@ -25,7 +23,6 @@ public function __construct() {

#[\Override]
public function register(IRegistrationContext $context): void {
$context->registerEventListener(ShareDeletedEvent::class, ShareDeletedListener::class);
}

#[\Override]
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@
namespace OCA\CloudFederationAPI\Controller;

use OC\AppFramework\Http\Attributes\FederationRateLimit;
use OC\Authentication\Token\PublicKeyTokenProvider;
use OC\OCM\OCMSignatoryManager;
use OCA\CloudFederationAPI\Config;
use OCA\CloudFederationAPI\Db\OcmTokenMapMapper;
use OCA\CloudFederationAPI\ResponseDefinitions;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
Expand All @@ -20,7 +18,6 @@
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\Attribute\PublicPage;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Federation\Exceptions\ActionNotSupportedException;
use OCP\Federation\Exceptions\AuthenticationFailedException;
Expand All @@ -41,7 +38,6 @@
use OCP\OCM\IOCMDiscoveryService;
use OCP\Security\Signature\Exceptions\IncomingRequestException;
use OCP\Security\Signature\IIncomingSignedRequest;
use OCP\Server;
use OCP\Share\Exceptions\ShareNotFound;
use Psr\Log\LoggerInterface;

Expand Down Expand Up @@ -70,7 +66,6 @@ public function __construct(
private ICloudFederationFactory $factory,
private ICloudIdManager $cloudIdManager,
private readonly IOCMDiscoveryService $ocmDiscoveryService,
private ITimeFactory $timeFactory,
) {
parent::__construct($appName, $request);
}
Expand Down Expand Up @@ -461,14 +456,7 @@ private function resolveNotificationIdentity(string $resourceType, array $notifi
try {
$provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType);
if ($provider instanceof ISignedCloudFederationProvider || $provider instanceof \NCU\Federation\ISignedCloudFederationProvider) {
$identity = $provider->getFederationIdFromSharedSecret($sharedSecret, $notification);
if ($identity === '') {
$tokenProvider = Server::get(PublicKeyTokenProvider::class);
$accessTokenDb = $tokenProvider->getToken($sharedSecret);
$mapping = Server::get(OcmTokenMapMapper::class)->getByAccessTokenId($accessTokenDb->getId());
$identity = $provider->getFederationIdFromSharedSecret($mapping->getRefreshToken(), $notification);
}
return $identity;
return $provider->getFederationIdFromSharedSecret($sharedSecret, $notification);
}
$this->logger->debug('cloud federation provider {provider} does not implement ISignedCloudFederationProvider', ['provider' => $provider::class]);
} catch (\Exception $e) {
Expand Down
69 changes: 8 additions & 61 deletions apps/cloud_federation_api/lib/Controller/TokenController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
namespace OCA\CloudFederationAPI\Controller;

use Firebase\JWT\JWT;
use OC\Authentication\Token\IProvider;
use OC\OCM\OCMSignatoryManager;
use OCA\CloudFederationAPI\Db\OcmTokenMap;
use OCA\CloudFederationAPI\Db\OcmTokenMapMapper;
use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
Expand All @@ -20,9 +17,6 @@
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Authentication\Exceptions\ExpiredTokenException;
use OCP\Authentication\Exceptions\InvalidTokenException;
use OCP\Authentication\Token\IToken;
use OCP\Federation\ICloudIdManager;
use OCP\IAppConfig;
use OCP\IRequest;
Expand All @@ -37,6 +31,7 @@
use OCP\Security\Signature\Model\Signatory;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager as IShareManager;
use OCP\Share\IShare;
use Psr\Log\LoggerInterface;

/**
Expand All @@ -46,14 +41,12 @@
class TokenController extends ApiController {
public function __construct(
IRequest $request,
private readonly IProvider $tokenProvider,
private readonly ISecureRandom $random,
private readonly ITimeFactory $timeFactory,
private readonly LoggerInterface $logger,
private readonly ISignatureManager $signatureManager,
private readonly OCMSignatoryManager $signatoryManager,
private readonly IAppConfig $appConfig,
private readonly OcmTokenMapMapper $ocmTokenMapMapper,
private readonly IShareManager $shareManager,
private readonly ICloudIdManager $cloudIdManager,
) {
Expand Down Expand Up @@ -203,37 +196,18 @@ public function accessToken(string $grant_type = '', string $code = ''): DataRes
$refreshToken = $code;

try {
$token = $this->tokenProvider->getToken($refreshToken);

if ($token->getType() !== IToken::PERMANENT_TOKEN) {
$this->logger->warning('Attempted to use non-permanent token as refresh token', [
'tokenId' => $token->getId(),
]);
$share = $this->shareManager->getShareByToken($refreshToken);
if (!in_array($share->getShareType(), [IShare::TYPE_REMOTE, IShare::TYPE_REMOTE_GROUP], true)
|| $share->getToken() === null
|| !hash_equals($share->getToken(), $refreshToken)
) {
return new DataResponse(
['error' => 'invalid_grant'],
Http::STATUS_UNAUTHORIZED
);
}

// After the first exchange the refresh token must only be usable to
// obtain further access tokens, never as a direct filesystem/WebDAV
// credential. Lock down its filesystem scope so a leaked refresh token
// cannot be replayed as a bearer against the WebDAV endpoints.
$scope = $token->getScopeAsArray();
if (($scope[IToken::SCOPE_FILESYSTEM] ?? true) !== false) {
$scope[IToken::SCOPE_FILESYSTEM] = false;
$token->setScope($scope);
$this->tokenProvider->updateToken($token);
}

// A refresh token may back several concurrent access tokens (e.g. the
// webdav mount and the webapp launcher exchange the same secret), so
// each exchange issues a fresh one and leaves the others in place;
// expiry and unshare cleanup revoke them.
$share = $this->shareManager->getShareByToken($refreshToken);
// access_token TTL from the refresh-token scope; default 3600, clamped 300..86400.
$ttl = (int)($token->getScopeAsArray()['ocm_access_token_ttl'] ?? 3600);
$expiresIn = max(300, min(86400, $ttl));
$expiresIn = 3600;
$issuedAt = $this->timeFactory->getTime();
$expiresAt = $issuedAt + $expiresIn;

Expand All @@ -258,46 +232,19 @@ public function accessToken(string $grant_type = '', string $code = ''): DataRes

$accessTokenString = JWT::encode($payload, $jwtKey, $jwtAlgorithm, $keyId, ['typ' => 'at+jwt']);

$accessToken = $this->tokenProvider->generateToken(
$accessTokenString,
$token->getUID(),
$token->getLoginName(),
null, // No password for access tokens
IToken::OCM_ACCESS_TOKEN_NAME,
IToken::TEMPORARY_TOKEN,
IToken::DO_NOT_REMEMBER
);

$accessToken->setExpires($expiresAt);
$this->tokenProvider->updateToken($accessToken);

$mapping = new OcmTokenMap();
$mapping->setAccessTokenId($accessToken->getId());
$mapping->setRefreshToken($refreshToken);
$mapping->setExpires($expiresAt);
$this->ocmTokenMapMapper->insert($mapping);

return new DataResponse([
'access_token' => $accessTokenString,
'token_type' => 'Bearer',
'expires_in' => $expiresIn,
], Http::STATUS_OK);
} catch (InvalidTokenException $e) {
} catch (ShareNotFound $e) {
$this->logger->info('Invalid refresh token provided', [
'exception' => $e,
]);
return new DataResponse(
['error' => 'invalid_grant'],
Http::STATUS_UNAUTHORIZED
);
} catch (ExpiredTokenException $e) {
$this->logger->info('Expired refresh token provided', [
'exception' => $e,
]);
return new DataResponse(
['error' => 'invalid_grant'],
Http::STATUS_UNAUTHORIZED
);
} catch (\Exception $e) {
$this->logger->error('Error generating access token', [
'exception' => $e,
Expand Down
41 changes: 0 additions & 41 deletions apps/cloud_federation_api/lib/Db/OcmTokenMap.php

This file was deleted.

Loading
Loading